WERROR check_published_printers(struct messaging_context *msg_ctx) { ADS_STATUS ads_rc; ADS_STRUCT *ads = NULL; int snum; int n_services = lp_numservices(); TALLOC_CTX *tmp_ctx = NULL; struct auth_session_info *session_info = NULL; struct spoolss_PrinterInfo2 *pinfo2; NTSTATUS status; WERROR result; char *old_krb5ccname = NULL; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) return WERR_NOMEM; ads = ads_init(lp_realm(), lp_workgroup(), NULL); if (!ads) { DEBUG(3, ("ads_init() failed\n")); return WERR_SERVER_UNAVAILABLE; } old_krb5ccname = getenv(KRB5_ENV_CCNAME); setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1); SAFE_FREE(ads->auth.password); ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); /* ads_connect() will find the DC for us */ ads_rc = ads_connect(ads); if (!ADS_ERR_OK(ads_rc)) { DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc))); result = WERR_ACCESS_DENIED; goto done; } status = make_session_info_system(tmp_ctx, &session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("check_published_printers: " "Could not create system session_info\n")); result = WERR_ACCESS_DENIED; goto done; } for (snum = 0; snum < n_services; snum++) { if (!lp_snum_ok(snum) || !lp_printable(snum)) { continue; } result = winreg_get_printer_internal(tmp_ctx, session_info, msg_ctx, lp_servicename(talloc_tos(), snum), &pinfo2); if (!W_ERROR_IS_OK(result)) { continue; } if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) { nt_printer_publish_ads(msg_ctx, ads, pinfo2); } TALLOC_FREE(pinfo2); } result = WERR_OK; done: ads_destroy(&ads); ads_kdestroy("MEMORY:prtpub_cache"); unsetenv(KRB5_ENV_CCNAME); if (old_krb5ccname) { setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0); } talloc_free(tmp_ctx); return result; }
/* * Because there is no good way to guarantee that a new xattr will be * created on file creation there might be no acl xattr on a file when * trying to read the acl. In this case the acl xattr will get * constructed at that time from the parent acl. * If the parent ACL doesn't have an xattr either the call will * recurse to the next parent directory until the share root is * reached. If the share root doesn't contain an ACL xattr either a * default ACL will be used. * Also a default ACL will be set if a non inheriting ACL is encountered. * * Basic algorithm: * read acl xattr blob * if acl xattr blob doesn't exist * stat current directory to know if it's a file or directory * read acl xattr blob from parent dir * acl xattr blob to smb nfs4 acl * calculate inherited smb nfs4 acl * without inheritance use default smb nfs4 acl * smb nfs4 acl to acl xattr blob * set acl xattr blob * return smb nfs4 acl * else * acl xattr blob to smb nfs4 acl * * Todo: Really use mem_ctx after fixing interface of nfs4_acls */ static struct SMB4ACL_T *nfs4acls_inheritacl(vfs_handle_struct *handle, const char *path, TALLOC_CTX *mem_ctx) { char *parent_dir = NULL; struct SMB4ACL_T *pparentacl = NULL; struct SMB4ACL_T *pchildacl = NULL; struct SMB4ACE_T *pace; SMB_ACE4PROP_T ace; bool isdir; struct smb_filename *smb_fname = NULL; NTSTATUS status; int ret; TALLOC_CTX *frame = talloc_stackframe(); DEBUG(10, ("nfs4acls_inheritacl invoked for %s\n", path)); smb_fname = synthetic_smb_fname(frame, path, NULL, NULL); if (smb_fname == NULL) { TALLOC_FREE(frame); errno = ENOMEM; return NULL; } ret = SMB_VFS_STAT(handle->conn, smb_fname); if (ret == -1) { DEBUG(0,("nfs4acls_inheritacl: failed to stat " "directory %s. Error was %s\n", smb_fname_str_dbg(smb_fname), strerror(errno))); TALLOC_FREE(frame); return NULL; } isdir = S_ISDIR(smb_fname->st.st_ex_mode); if (!parent_dirname(talloc_tos(), path, &parent_dir, NULL)) { TALLOC_FREE(frame); errno = ENOMEM; return NULL; } status = nfs4_get_nfs4_acl(handle, frame, parent_dir, &pparentacl); if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND) && strncmp(parent_dir, ".", 2) != 0) { pparentacl = nfs4acls_inheritacl(handle, parent_dir, frame); } else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { pparentacl = nfs4acls_defaultacl(frame); } else if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); return NULL; } pchildacl = smb_create_smb4acl(mem_ctx); if (pchildacl == NULL) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(frame); errno = ENOMEM; return NULL; } for (pace = smb_first_ace4(pparentacl); pace != NULL; pace = smb_next_ace4(pace)) { struct SMB4ACE_T *pchildace; ace = *smb_get_ace4(pace); if ((isdir && !(ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) || (!isdir && !(ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE))) { DEBUG(10, ("non inheriting ace type: %d, iflags: %x, " "flags: %x, mask: %x, who: %d\n", ace.aceType, ace.flags, ace.aceFlags, ace.aceMask, ace.who.id)); continue; } DEBUG(10, ("inheriting ace type: %d, iflags: %x, " "flags: %x, mask: %x, who: %d\n", ace.aceType, ace.flags, ace.aceFlags, ace.aceMask, ace.who.id)); ace.aceFlags |= SMB_ACE4_INHERITED_ACE; if (ace.aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) { ace.aceFlags &= ~SMB_ACE4_INHERIT_ONLY_ACE; } if (ace.aceFlags & SMB_ACE4_NO_PROPAGATE_INHERIT_ACE) { ace.aceFlags &= ~SMB_ACE4_FILE_INHERIT_ACE; ace.aceFlags &= ~SMB_ACE4_DIRECTORY_INHERIT_ACE; ace.aceFlags &= ~SMB_ACE4_NO_PROPAGATE_INHERIT_ACE; } pchildace = smb_add_ace4(pchildacl, &ace); if (pchildace == NULL) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(frame); errno = ENOMEM; return NULL; } } /* Set a default ACL if we didn't inherit anything. */ if (smb_first_ace4(pchildacl) == NULL) { TALLOC_FREE(pchildacl); pchildacl = nfs4acls_defaultacl(mem_ctx); } /* store the returned ACL to get it directly in the future and avoid dynamic inheritance behavior. */ nfs4acl_xattr_set_smb4acl(handle, path, pchildacl); TALLOC_FREE(frame); return pchildacl; }
NTSTATUS unix_convert(TALLOC_CTX *ctx, connection_struct *conn, const char *orig_path, struct smb_filename **smb_fname_out, uint32_t ucf_flags) { struct smb_filename *smb_fname = NULL; char *start, *end; char *dirpath = NULL; char *stream = NULL; bool component_was_mangled = False; bool name_has_wildcard = False; bool posix_pathnames = false; bool allow_wcard_last_component = (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP); bool save_last_component = ucf_flags & UCF_SAVE_LCOMP; NTSTATUS status; int ret = -1; *smb_fname_out = NULL; smb_fname = talloc_zero(ctx, struct smb_filename); if (smb_fname == NULL) { return NT_STATUS_NO_MEMORY; } if (conn->printer) { /* we don't ever use the filenames on a printer share as a filename - so don't convert them */ if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) { status = NT_STATUS_NO_MEMORY; goto err; } goto done; } DEBUG(5, ("unix_convert called on file \"%s\"\n", orig_path)); /* * Conversion to basic unix format is already done in * check_path_syntax(). */ /* * Names must be relative to the root of the service - any leading /. * and trailing /'s should have been trimmed by check_path_syntax(). */ #ifdef DEVELOPER SMB_ASSERT(*orig_path != '/'); #endif /* * If we trimmed down to a single '\0' character * then we should use the "." directory to avoid * searching the cache, but not if we are in a * printing share. * As we know this is valid we can return true here. */ if (!*orig_path) { if (!(smb_fname->base_name = talloc_strdup(smb_fname, "."))) { status = NT_STATUS_NO_MEMORY; goto err; } if (SMB_VFS_STAT(conn, smb_fname) != 0) { status = map_nt_error_from_unix(errno); goto err; } DEBUG(5, ("conversion finished \"\" -> %s\n", smb_fname->base_name)); goto done; } if (orig_path[0] == '.' && (orig_path[1] == '/' || orig_path[1] == '\0')) { /* Start of pathname can't be "." only. */ if (orig_path[1] == '\0' || orig_path[2] == '\0') { status = NT_STATUS_OBJECT_NAME_INVALID; } else { status =determine_path_error(&orig_path[2], allow_wcard_last_component); } goto err; } /* Start with the full orig_path as given by the caller. */ if (!(smb_fname->base_name = talloc_strdup(smb_fname, orig_path))) { DEBUG(0, ("talloc_strdup failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } /* * Large directory fix normalization. If we're case sensitive, and * the case preserving parameters are set to "no", normalize the case of * the incoming filename from the client WHETHER IT EXISTS OR NOT ! * This is in conflict with the current (3.0.20) man page, but is * what people expect from the "large directory howto". I'll update * the man page. Thanks to [email protected] for finding this. JRA. */ if (conn->case_sensitive && !conn->case_preserve && !conn->short_case_preserve) { strnorm(smb_fname->base_name, lp_defaultcase(SNUM(conn))); } /* * Ensure saved_last_component is valid even if file exists. */ if(save_last_component) { end = strrchr_m(smb_fname->base_name, '/'); if (end) { smb_fname->original_lcomp = talloc_strdup(smb_fname, end + 1); } else { smb_fname->original_lcomp = talloc_strdup(smb_fname, smb_fname->base_name); } if (smb_fname->original_lcomp == NULL) { status = NT_STATUS_NO_MEMORY; goto err; } } posix_pathnames = (lp_posix_pathnames() || (ucf_flags & UCF_POSIX_PATHNAMES)); /* * Strip off the stream, and add it back when we're done with the * base_name. */ if (!posix_pathnames) { stream = strchr_m(smb_fname->base_name, ':'); if (stream != NULL) { char *tmp = talloc_strdup(smb_fname, stream); if (tmp == NULL) { status = NT_STATUS_NO_MEMORY; goto err; } /* * Since this is actually pointing into * smb_fname->base_name this truncates base_name. */ *stream = '\0'; stream = tmp; } } start = smb_fname->base_name; /* * If we're providing case insensitive semantics or * the underlying filesystem is case insensitive, * then a case-normalized hit in the stat-cache is * authoratitive. JRA. * * Note: We're only checking base_name. The stream_name will be * added and verified in build_stream_path(). */ if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && stat_cache_lookup(conn, posix_pathnames, &smb_fname->base_name, &dirpath, &start, &smb_fname->st)) { goto done; } /* * Make sure "dirpath" is an allocated string, we use this for * building the directories with talloc_asprintf and free it. */ if ((dirpath == NULL) && (!(dirpath = talloc_strdup(ctx,"")))) { DEBUG(0, ("talloc_strdup failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } /* * If we have a wildcard we must walk the path to * find where the error is, even if case sensitive * is true. */ name_has_wildcard = ms_has_wild(smb_fname->base_name); if (name_has_wildcard && !allow_wcard_last_component) { /* Wildcard not valid anywhere. */ status = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n", smb_fname->base_name, dirpath, start)); if (!name_has_wildcard) { /* * stat the name - if it exists then we can add the stream back (if * there was one) and be done! */ if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn, smb_fname); } else { ret = SMB_VFS_STAT(conn, smb_fname); } if (ret == 0) { status = check_for_dot_component(smb_fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } /* Add the path (not including the stream) to the cache. */ stat_cache_add(orig_path, smb_fname->base_name, conn->case_sensitive); DEBUG(5,("conversion of base_name finished %s -> %s\n", orig_path, smb_fname->base_name)); goto done; } /* Stat failed - ensure we don't use it. */ SET_STAT_INVALID(smb_fname->st); if (errno == ENOENT) { /* Optimization when creating a new file - only the last component doesn't exist. */ status = check_parent_exists(ctx, conn, posix_pathnames, smb_fname, &dirpath, &start); if (!NT_STATUS_IS_OK(status)) { goto fail; } } /* * A special case - if we don't have any wildcards or mangling chars and are case * sensitive or the underlying filesystem is case insensitive then searching * won't help. */ if ((conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && !mangle_is_mangled(smb_fname->base_name, conn->params)) { status = check_for_dot_component(smb_fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } /* * The stat failed. Could be ok as it could be * a new file. */ if (errno == ENOTDIR || errno == ELOOP) { status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } else if (errno == ENOENT) { /* * Was it a missing last component ? * or a missing intermediate component ? */ struct smb_filename parent_fname; const char *last_component = NULL; ZERO_STRUCT(parent_fname); if (!parent_dirname(ctx, smb_fname->base_name, &parent_fname.base_name, &last_component)) { status = NT_STATUS_NO_MEMORY; goto fail; } if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn, &parent_fname); } else { ret = SMB_VFS_STAT(conn, &parent_fname); } if (ret == -1) { if (errno == ENOTDIR || errno == ENOENT || errno == ELOOP) { status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } } /* * Missing last component is ok - new file. * Also deal with permission denied elsewhere. * Just drop out to done. */ goto done; } } } else { /* * We have a wildcard in the pathname. * * Optimization for common case where the wildcard * is in the last component and the client already * sent the correct case. */ status = check_parent_exists(ctx, conn, posix_pathnames, smb_fname, &dirpath, &start); if (!NT_STATUS_IS_OK(status)) { goto fail; } } /* * is_mangled() was changed to look at an entire pathname, not * just a component. JRA. */ if (mangle_is_mangled(start, conn->params)) { component_was_mangled = True; } /* * Now we need to recursively match the name against the real * directory structure. */ /* * Match each part of the path name separately, trying the names * as is first, then trying to scan the directory for matching names. */ for (; start ; start = (end?end+1:(char *)NULL)) { /* * Pinpoint the end of this section of the filename. */ /* mb safe. '/' can't be in any encoded char. */ end = strchr(start, '/'); /* * Chop the name at this point. */ if (end) { *end = 0; } if (save_last_component) { TALLOC_FREE(smb_fname->original_lcomp); smb_fname->original_lcomp = talloc_strdup(smb_fname, end ? end + 1 : start); if (!smb_fname->original_lcomp) { DEBUG(0, ("talloc failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } } /* The name cannot have a component of "." */ if (ISDOT(start)) { if (!end) { /* Error code at the end of a pathname. */ status = NT_STATUS_OBJECT_NAME_INVALID; } else { status = determine_path_error(end+1, allow_wcard_last_component); } goto fail; } /* The name cannot have a wildcard if it's not the last component. */ name_has_wildcard = ms_has_wild(start); /* Wildcards never valid within a pathname. */ if (name_has_wildcard && end) { status = NT_STATUS_OBJECT_NAME_INVALID; goto fail; } /* Skip the stat call if it's a wildcard end. */ if (name_has_wildcard) { DEBUG(5,("Wildcard %s\n",start)); goto done; } /* * Check if the name exists up to this point. */ if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn, smb_fname); } else { ret = SMB_VFS_STAT(conn, smb_fname); } if (ret == 0) { /* * It exists. it must either be a directory or this must * be the last part of the path for it to be OK. */ if (end && !S_ISDIR(smb_fname->st.st_ex_mode)) { /* * An intermediate part of the name isn't * a directory. */ DEBUG(5,("Not a dir %s\n",start)); *end = '/'; /* * We need to return the fact that the * intermediate name resolution failed. This * is used to return an error of ERRbadpath * rather than ERRbadfile. Some Windows * applications depend on the difference between * these two errors. */ status = NT_STATUS_OBJECT_PATH_NOT_FOUND; goto fail; } } else { char *found_name = NULL; /* Stat failed - ensure we don't use it. */ SET_STAT_INVALID(smb_fname->st); /* * Reset errno so we can detect * directory open errors. */ errno = 0; /* * Try to find this part of the path in the directory. */ if (name_has_wildcard || (get_real_filename(conn, dirpath, start, talloc_tos(), &found_name) == -1)) { char *unmangled; if (end) { /* * An intermediate part of the name * can't be found. */ DEBUG(5,("Intermediate not found %s\n", start)); *end = '/'; /* * We need to return the fact that the * intermediate name resolution failed. * This is used to return an error of * ERRbadpath rather than ERRbadfile. * Some Windows applications depend on * the difference between these two * errors. */ /* * ENOENT, ENOTDIR and ELOOP all map * to NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP) { status = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { status = map_nt_error_from_unix(errno); } goto fail; } /* * ENOENT/EACCESS are the only valid errors * here. EACCESS needs handling here for * "dropboxes", i.e. directories where users * can only put stuff with permission -wx. */ if ((errno != 0) && (errno != ENOENT) && (errno != EACCES)) { /* * ENOTDIR and ELOOP both map to * NT_STATUS_OBJECT_PATH_NOT_FOUND * in the filename walk. */ if (errno == ENOTDIR || errno == ELOOP) { status = NT_STATUS_OBJECT_PATH_NOT_FOUND; } else { status = map_nt_error_from_unix(errno); } goto fail; } /* * Just the last part of the name doesn't exist. * We need to strupper() or strlower() it as * this conversion may be used for file creation * purposes. Fix inspired by * Thomas Neumann <*****@*****.**>. */ if (!conn->case_preserve || (mangle_is_8_3(start, False, conn->params) && !conn->short_case_preserve)) { strnorm(start, lp_defaultcase(SNUM(conn))); } /* * check on the mangled stack to see if we can * recover the base of the filename. */ if (mangle_is_mangled(start, conn->params) && mangle_lookup_name_from_8_3(ctx, start, &unmangled, conn->params)) { char *tmp; size_t start_ofs = start - smb_fname->base_name; if (*dirpath != '\0') { tmp = talloc_asprintf( smb_fname, "%s/%s", dirpath, unmangled); TALLOC_FREE(unmangled); } else { tmp = unmangled; } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } TALLOC_FREE(smb_fname->base_name); smb_fname->base_name = tmp; start = smb_fname->base_name + start_ofs; end = start + strlen(start); } DEBUG(5,("New file %s\n",start)); goto done; } /* * Restore the rest of the string. If the string was * mangled the size may have changed. */ if (end) { char *tmp; size_t start_ofs = start - smb_fname->base_name; if (*dirpath != '\0') { tmp = talloc_asprintf(smb_fname, "%s/%s/%s", dirpath, found_name, end+1); } else { tmp = talloc_asprintf(smb_fname, "%s/%s", found_name, end+1); } if (tmp == NULL) { DEBUG(0, ("talloc_asprintf failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } TALLOC_FREE(smb_fname->base_name); smb_fname->base_name = tmp; start = smb_fname->base_name + start_ofs; end = start + strlen(found_name); *end = '\0'; } else { char *tmp; size_t start_ofs = start - smb_fname->base_name; if (*dirpath != '\0') { tmp = talloc_asprintf(smb_fname, "%s/%s", dirpath, found_name); } else { tmp = talloc_strdup(smb_fname, found_name); } if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } TALLOC_FREE(smb_fname->base_name); smb_fname->base_name = tmp; start = smb_fname->base_name + start_ofs; /* * We just scanned for, and found the end of * the path. We must return a valid stat struct * if it exists. JRA. */ if (posix_pathnames) { ret = SMB_VFS_LSTAT(conn, smb_fname); } else { ret = SMB_VFS_STAT(conn, smb_fname); } if (ret != 0) { SET_STAT_INVALID(smb_fname->st); } } TALLOC_FREE(found_name); } /* end else */ #ifdef DEVELOPER /* * This sucks! * We should never provide different behaviors * depending on DEVELOPER!!! */ if (VALID_STAT(smb_fname->st)) { bool delete_pending; uint32_t name_hash; status = file_name_hash(conn, smb_fname_str_dbg(smb_fname), &name_hash); if (!NT_STATUS_IS_OK(status)) { goto fail; } get_file_infos(vfs_file_id_from_sbuf(conn, &smb_fname->st), name_hash, &delete_pending, NULL); if (delete_pending) { status = NT_STATUS_DELETE_PENDING; goto fail; } } #endif /* * Add to the dirpath that we have resolved so far. */ if (*dirpath != '\0') { char *tmp = talloc_asprintf(ctx, "%s/%s", dirpath, start); if (!tmp) { DEBUG(0, ("talloc_asprintf failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } TALLOC_FREE(dirpath); dirpath = tmp; } else { TALLOC_FREE(dirpath); if (!(dirpath = talloc_strdup(ctx,start))) { DEBUG(0, ("talloc_strdup failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } } /* * Cache the dirpath thus far. Don't cache a name with mangled * or wildcard components as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, dirpath, conn->case_sensitive); } /* * Restore the / that we wiped out earlier. */ if (end) { *end = '/'; } } /* * Cache the full path. Don't cache a name with mangled or wildcard * components as this can change the size. */ if(!component_was_mangled && !name_has_wildcard) { stat_cache_add(orig_path, smb_fname->base_name, conn->case_sensitive); } /* * The name has been resolved. */ DEBUG(5,("conversion finished %s -> %s\n", orig_path, smb_fname->base_name)); done: /* Add back the stream if one was stripped off originally. */ if (stream != NULL) { smb_fname->stream_name = stream; /* Check path now that the base_name has been converted. */ status = build_stream_path(ctx, conn, orig_path, smb_fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } } TALLOC_FREE(dirpath); *smb_fname_out = smb_fname; return NT_STATUS_OK; fail: DEBUG(10, ("dirpath = [%s] start = [%s]\n", dirpath, start)); if (*dirpath != '\0') { smb_fname->base_name = talloc_asprintf(smb_fname, "%s/%s", dirpath, start); } else { smb_fname->base_name = talloc_strdup(smb_fname, start); } if (!smb_fname->base_name) { DEBUG(0, ("talloc_asprintf failed\n")); status = NT_STATUS_NO_MEMORY; goto err; } *smb_fname_out = smb_fname; TALLOC_FREE(dirpath); return status; err: TALLOC_FREE(smb_fname); return status; }
/* parse a negTokenInit packet giving a GUID, a list of supported OIDs (the mechanisms) and a principal name string */ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx, DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], char **principal, DATA_BLOB *secblob) { int i; bool ret = false; ASN1_DATA *data; for (i = 0; i < ASN1_MAX_OIDS; i++) { OIDs[i] = NULL; } if (principal) { *principal = NULL; } if (secblob) { *secblob = data_blob_null; } data = asn1_init(talloc_tos()); if (data == NULL) { return false; } if (!asn1_load(data, blob)) goto err; if (!asn1_start_tag(data,ASN1_APPLICATION(0))) goto err; if (!asn1_check_OID(data,OID_SPNEGO)) goto err; /* negTokenInit [0] NegTokenInit */ if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err; if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err; /* mechTypes [0] MechTypeList OPTIONAL */ /* Not really optional, we depend on this to decide * what mechanisms we have to work with. */ if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err; if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err; for (i=0; asn1_tag_remaining(data) > 0 && i < ASN1_MAX_OIDS-1; i++) { if (!asn1_read_OID(data,ctx, &OIDs[i])) { goto err; } if (asn1_has_error(data)) { goto err; } } OIDs[i] = NULL; if (!asn1_end_tag(data)) goto err; if (!asn1_end_tag(data)) goto err; /* Win7 + Live Sign-in Assistant attaches a mechToken ASN1_CONTEXT(2) to the negTokenInit packet which breaks our negotiation if we just assume the next tag is ASN1_CONTEXT(3). */ if (asn1_peek_tag(data, ASN1_CONTEXT(1))) { uint8_t flags; /* reqFlags [1] ContextFlags OPTIONAL */ if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err; if (!asn1_start_tag(data, ASN1_BIT_STRING)) goto err; while (asn1_tag_remaining(data) > 0) { if (!asn1_read_uint8(data, &flags)) goto err; } if (!asn1_end_tag(data)) goto err; if (!asn1_end_tag(data)) goto err; } if (asn1_peek_tag(data, ASN1_CONTEXT(2))) { DATA_BLOB sblob = data_blob_null; /* mechToken [2] OCTET STRING OPTIONAL */ if (!asn1_start_tag(data, ASN1_CONTEXT(2))) goto err; if (!asn1_read_OctetString(data, ctx, &sblob)) goto err; if (!asn1_end_tag(data)) { data_blob_free(&sblob); goto err; } if (secblob) { *secblob = sblob; } else { data_blob_free(&sblob); } } if (asn1_peek_tag(data, ASN1_CONTEXT(3))) { char *princ = NULL; /* mechListMIC [3] OCTET STRING OPTIONAL */ if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto err; if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err; if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto err; if (!asn1_read_GeneralString(data, ctx, &princ)) goto err; if (!asn1_end_tag(data)) goto err; if (!asn1_end_tag(data)) goto err; if (!asn1_end_tag(data)) goto err; if (principal) { *principal = princ; } else { TALLOC_FREE(princ); } } if (!asn1_end_tag(data)) goto err; if (!asn1_end_tag(data)) goto err; if (!asn1_end_tag(data)) goto err; ret = !asn1_has_error(data); err: if (asn1_has_error(data)) { int j; if (principal) { TALLOC_FREE(*principal); } if (secblob) { data_blob_free(secblob); } for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) { TALLOC_FREE(OIDs[j]); } } asn1_free(data); return ret; }
/* parse a SPNEGO auth packet. This contains the encrypted passwords */ bool spnego_parse_auth_response(TALLOC_CTX *ctx, DATA_BLOB blob, NTSTATUS nt_status, const char *mechOID, DATA_BLOB *auth) { ASN1_DATA *data; uint8_t negResult; bool ret = false; if (NT_STATUS_IS_OK(nt_status)) { negResult = SPNEGO_ACCEPT_COMPLETED; } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { negResult = SPNEGO_ACCEPT_INCOMPLETE; } else { negResult = SPNEGO_REJECT; } data = asn1_init(talloc_tos()); if (data == NULL) { return false; } *auth = data_blob_null; if (!asn1_load(data, blob)) goto err; if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err; if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err; if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto err; if (!asn1_check_enumerated(data, negResult)) goto err; if (!asn1_end_tag(data)) goto err; if (asn1_tag_remaining(data)) { if (!asn1_start_tag(data,ASN1_CONTEXT(1))) goto err; if (!asn1_check_OID(data, mechOID)) goto err; if (!asn1_end_tag(data)) goto err; if (asn1_tag_remaining(data)) { if (!asn1_start_tag(data,ASN1_CONTEXT(2))) goto err; if (!asn1_read_OctetString(data, ctx, auth)) goto err; if (!asn1_end_tag(data)) goto err; } } else if (negResult == SPNEGO_ACCEPT_INCOMPLETE) { asn1_set_error(data); goto err; } /* Binding against Win2K DC returns a duplicate of the responseToken in * the optional mechListMIC field. This is a bug in Win2K. We ignore * this field if it exists. Win2K8 may return a proper mechListMIC at * which point we need to implement the integrity checking. */ if (asn1_tag_remaining(data)) { DATA_BLOB mechList = data_blob_null; if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto err; if (!asn1_read_OctetString(data, ctx, &mechList)) goto err; data_blob_free(&mechList); if (!asn1_end_tag(data)) goto err; DEBUG(5,("spnego_parse_auth_response received mechListMIC, " "ignoring.\n")); } if (!asn1_end_tag(data)) goto err; if (!asn1_end_tag(data)) goto err; ret = !asn1_has_error(data); err: if (asn1_has_error(data)) { DEBUG(3, ("spnego_parse_auth_response failed at %d\n", (int)asn1_current_ofs(data))); asn1_free(data); data_blob_free(auth); return false; } asn1_free(data); return ret; }
static NTSTATUS fset_nt_acl_tdb(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd) { NTSTATUS status; DATA_BLOB blob; if (DEBUGLEVEL >= 10) { DEBUG(10,("fset_nt_acl_tdb: incoming sd for file %s\n", fsp->fsp_name)); NDR_PRINT_DEBUG(security_descriptor, CONST_DISCARD(struct security_descriptor *,psd)); } status = SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd); if (!NT_STATUS_IS_OK(status)) { return status; } /* Ensure owner and group are set. */ if (!psd->owner_sid || !psd->group_sid) { int ret; SMB_STRUCT_STAT sbuf; DOM_SID owner_sid, group_sid; struct security_descriptor *nc_psd = dup_sec_desc(talloc_tos(), psd); if (!nc_psd) { return NT_STATUS_OK; } if (fsp->is_directory || fsp->fh->fd == -1) { if (fsp->posix_open) { ret = SMB_VFS_LSTAT(fsp->conn,fsp->fsp_name, &sbuf); } else { ret = SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf); } } else { ret = SMB_VFS_FSTAT(fsp, &sbuf); } if (ret == -1) { /* Lower level acl set succeeded, * so still return OK. */ return NT_STATUS_OK; } create_file_sids(&sbuf, &owner_sid, &group_sid); /* This is safe as nc_psd is discarded at fn exit. */ nc_psd->owner_sid = &owner_sid; nc_psd->group_sid = &group_sid; security_info_sent |= (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION); psd = nc_psd; } #if 0 if ((security_info_sent & DACL_SECURITY_INFORMATION) && psd->dacl != NULL && (psd->type & (SE_DESC_DACL_AUTO_INHERITED| SE_DESC_DACL_AUTO_INHERIT_REQ))== (SE_DESC_DACL_AUTO_INHERITED| SE_DESC_DACL_AUTO_INHERIT_REQ) ) { struct security_descriptor *new_psd = NULL; status = append_parent_acl(fsp, psd, &new_psd); if (!NT_STATUS_IS_OK(status)) { /* Lower level acl set succeeded, * so still return OK. */ return NT_STATUS_OK; } psd = new_psd; } #endif if (DEBUGLEVEL >= 10) { DEBUG(10,("fset_nt_acl_tdb: storing tdb sd for file %s\n", fsp->fsp_name)); NDR_PRINT_DEBUG(security_descriptor, CONST_DISCARD(struct security_descriptor *,psd)); } create_acl_blob(psd, &blob); store_acl_blob_fsp(handle, fsp, &blob); return NT_STATUS_OK; }
static void filter_request(char *buf, size_t buf_len) { int msg_type = CVAL(buf,0); int type = CVAL(buf,smb_com); unsigned x; fstring name1,name2; int name_len1 = 0; int name_len2; int name_type1, name_type2; if (msg_type) { /* it's a netbios special */ switch (msg_type) case 0x81: /* session request */ /* inbuf_size is guaranteed to be at least 4. */ name_len1 = name_len((unsigned char *)(buf+4), buf_len - 4); if (name_len1 <= 0 || name_len1 > buf_len - 4) { DEBUG(0,("Invalid name length in session request\n")); return; } name_len2 = name_len((unsigned char *)(buf+4+name_len1), buf_len - 4 - name_len1); if (name_len2 <= 0 || name_len2 > buf_len - 4 - name_len1) { DEBUG(0,("Invalid name length in session request\n")); return; } name_type1 = name_extract((unsigned char *)buf, buf_len,(unsigned int)4,name1); name_type2 = name_extract((unsigned char *)buf, buf_len,(unsigned int)(4 + name_len1),name2); if (name_type1 == -1 || name_type2 == -1) { DEBUG(0,("Invalid name type in session request\n")); return; } d_printf("sesion_request: %s -> %s\n", name1, name2); if (netbiosname) { char *mangled = name_mangle( talloc_tos(), netbiosname, 0x20); if (mangled != NULL) { /* replace the destination netbios * name */ memcpy(buf+4, mangled, name_len((unsigned char *)mangled, talloc_get_size(mangled))); TALLOC_FREE(mangled); } } return; } /* it's an ordinary SMB request */ switch (type) { case SMBsesssetupX: /* force the client capabilities */ x = IVAL(buf,smb_vwv11); d_printf("SMBsesssetupX cap=0x%08x\n", x); d_printf("pwlen=%d/%d\n", SVAL(buf, smb_vwv7), SVAL(buf, smb_vwv8)); system("mv sessionsetup.dat sessionsetup1.dat"); save_file("sessionsetup.dat", smb_buf(buf), SVAL(buf, smb_vwv7)); x = (x | CLI_CAPABILITY_SET) & ~CLI_CAPABILITY_MASK; SIVAL(buf, smb_vwv11, x); break; } }
/** * add a value to a key. */ static sbcErr smbconf_reg_set_value(struct registry_key *key, const char *valname, const char *valstr) { struct registry_value val; WERROR werr = WERR_OK; sbcErr err; char *subkeyname; const char *canon_valname; const char *canon_valstr; if (!lp_canonicalize_parameter_with_value(valname, valstr, &canon_valname, &canon_valstr)) { if (canon_valname == NULL) { DEBUG(5, ("invalid parameter '%s' given\n", valname)); } else { DEBUG(5, ("invalid value '%s' given for " "parameter '%s'\n", valstr, valname)); } err = SBC_ERR_INVALID_PARAM; goto done; } if (smbconf_reg_valname_forbidden(canon_valname)) { DEBUG(5, ("Parameter '%s' not allowed in registry.\n", canon_valname)); err = SBC_ERR_INVALID_PARAM; goto done; } subkeyname = strrchr_m(key->key->name, '\\'); if ((subkeyname == NULL) || (*(subkeyname +1) == '\0')) { DEBUG(5, ("Invalid registry key '%s' given as " "smbconf section.\n", key->key->name)); err = SBC_ERR_INVALID_PARAM; goto done; } subkeyname++; if (!strequal(subkeyname, GLOBAL_NAME) && lp_parameter_is_global(valname)) { DEBUG(5, ("Global parameter '%s' not allowed in " "service definition ('%s').\n", canon_valname, subkeyname)); err = SBC_ERR_INVALID_PARAM; goto done; } ZERO_STRUCT(val); val.type = REG_SZ; if (!push_reg_sz(talloc_tos(), &val.data, canon_valstr)) { err = SBC_ERR_NOMEM; goto done; } werr = reg_setvalue(key, canon_valname, &val); if (!W_ERROR_IS_OK(werr)) { DEBUG(5, ("Error adding value '%s' to " "key '%s': %s\n", canon_valname, key->key->name, win_errstr(werr))); err = SBC_ERR_NOMEM; goto done; } err = SBC_ERR_OK; done: return err; }
void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state) { struct winbindd_domain *domain; fstring name_domain, name_user; NTSTATUS result = NT_STATUS_NOT_SUPPORTED; struct WINBINDD_MEMORY_CREDS *entry; DATA_BLOB initial, challenge, auth; uint32_t initial_blob_len, challenge_blob_len, extra_len; /* Ensure null termination */ state->request->data.ccache_ntlm_auth.user[ sizeof(state->request->data.ccache_ntlm_auth.user)-1]='\0'; DEBUG(3, ("[%5lu]: perform NTLM auth on behalf of user %s\n", (unsigned long)state->pid, state->request->data.ccache_ntlm_auth.user)); /* Parse domain and username */ if (!canonicalize_username(state->request->data.ccache_ntlm_auth.user, name_domain, name_user)) { DEBUG(5,("winbindd_ccache_ntlm_auth: cannot parse domain and user from name [%s]\n", state->request->data.ccache_ntlm_auth.user)); request_error(state); return; } domain = find_auth_domain(state->request->flags, name_domain); if (domain == NULL) { DEBUG(5,("winbindd_ccache_ntlm_auth: can't get domain [%s]\n", name_domain)); request_error(state); return; } if (!check_client_uid(state, state->request->data.ccache_ntlm_auth.uid)) { request_error(state); return; } /* validate blob lengths */ initial_blob_len = state->request->data.ccache_ntlm_auth.initial_blob_len; challenge_blob_len = state->request->data.ccache_ntlm_auth.challenge_blob_len; extra_len = state->request->extra_len; if (initial_blob_len > extra_len || challenge_blob_len > extra_len || initial_blob_len + challenge_blob_len > extra_len || initial_blob_len + challenge_blob_len < initial_blob_len || initial_blob_len + challenge_blob_len < challenge_blob_len) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: blob lengths overrun " "or wrap. Buffer [%d+%d > %d]\n", initial_blob_len, challenge_blob_len, extra_len)); goto process_result; } /* Parse domain and username */ if (!parse_domain_user(state->request->data.ccache_ntlm_auth.user, name_domain, name_user)) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: cannot parse " "domain and user from name [%s]\n", state->request->data.ccache_ntlm_auth.user)); goto process_result; } entry = find_memory_creds_by_name(state->request->data.ccache_ntlm_auth.user); if (entry == NULL || entry->nt_hash == NULL || entry->lm_hash == NULL) { DEBUG(10,("winbindd_dual_ccache_ntlm_auth: could not find " "credentials for user %s\n", state->request->data.ccache_ntlm_auth.user)); goto process_result; } DEBUG(10,("winbindd_dual_ccache_ntlm_auth: found ccache [%s]\n", entry->username)); if (!client_can_access_ccache_entry(state->request->data.ccache_ntlm_auth.uid, entry)) { goto process_result; } if (initial_blob_len == 0 && challenge_blob_len == 0) { /* this is just a probe to see if credentials are available. */ result = NT_STATUS_OK; state->response->data.ccache_ntlm_auth.auth_blob_len = 0; goto process_result; } initial = data_blob_const(state->request->extra_data.data, initial_blob_len); challenge = data_blob_const( state->request->extra_data.data + initial_blob_len, state->request->data.ccache_ntlm_auth.challenge_blob_len); result = do_ntlm_auth_with_stored_pw( name_user, name_domain, entry->pass, initial, challenge, talloc_tos(), &auth, state->response->data.ccache_ntlm_auth.session_key); if (!NT_STATUS_IS_OK(result)) { goto process_result; } state->response->extra_data.data = talloc_memdup( state->mem_ctx, auth.data, auth.length); if (!state->response->extra_data.data) { result = NT_STATUS_NO_MEMORY; goto process_result; } state->response->length += auth.length; state->response->data.ccache_ntlm_auth.auth_blob_len = auth.length; data_blob_free(&auth); process_result: if (!NT_STATUS_IS_OK(result)) { request_error(state); return; } request_ok(state); }
static int process_root(int local_flags) { struct passwd *pwd; int result = 0; char *old_passwd = NULL; if (local_flags & LOCAL_SET_LDAP_ADMIN_PW) { char *ldap_admin_dn = lp_ldap_admin_dn(talloc_tos()); if ( ! *ldap_admin_dn ) { DEBUG(0,("ERROR: 'ldap admin dn' not defined! Please check your smb.conf\n")); goto done; } printf("Setting stored password for \"%s\" in secrets.tdb\n", ldap_admin_dn); if ( ! *ldap_secret ) { new_passwd = prompt_for_new_password(stdin_passwd_get); if (new_passwd == NULL) { fprintf(stderr, "Failed to read new password!\n"); exit(1); } fstrcpy(ldap_secret, new_passwd); } if (!store_ldap_admin_pw(ldap_secret)) { DEBUG(0,("ERROR: Failed to store the ldap admin password!\n")); } goto done; } /* Ensure passdb startup(). */ if(!initialize_password_db(False, NULL)) { DEBUG(0, ("Failed to open passdb!\n")); exit(1); } /* Ensure we have a SAM sid. */ get_global_sam_sid(); /* * Ensure both add/delete user are not set * Ensure add/delete user and either remote machine or join domain are * not both set. */ if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) || ((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) && (remote_machine != NULL))) { usage(); } /* Only load interfaces if we are doing network operations. */ if (remote_machine) { load_interfaces(); } if (!user_name[0] && (pwd = getpwuid_alloc(talloc_tos(), geteuid()))) { fstrcpy(user_name, pwd->pw_name); TALLOC_FREE(pwd); } if (!user_name[0]) { fprintf(stderr,"You must specify a username\n"); exit(1); } if (local_flags & LOCAL_TRUST_ACCOUNT) { /* add the $ automatically */ static fstring buf; /* * Remove any trailing '$' before we * generate the initial machine password. */ if (user_name[strlen(user_name)-1] == '$') { user_name[strlen(user_name)-1] = 0; } if (local_flags & LOCAL_ADD_USER) { SAFE_FREE(new_passwd); new_passwd = smb_xstrdup(user_name); if (!strlower_m(new_passwd)) { fprintf(stderr, "strlower_m %s failed\n", new_passwd); exit(1); } } /* * Now ensure the username ends in '$' for * the machine add. */ slprintf(buf, sizeof(buf)-1, "%s$", user_name); strlcpy(user_name, buf, sizeof(user_name)); } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) { static fstring buf; if ((local_flags & LOCAL_ADD_USER) && (new_passwd == NULL)) { /* * Prompt for trusting domain's account password */ new_passwd = prompt_for_new_password(stdin_passwd_get); if(!new_passwd) { fprintf(stderr, "Unable to get newpassword.\n"); exit(1); } } /* prepare uppercased and '$' terminated username */ slprintf(buf, sizeof(buf) - 1, "%s$", user_name); strlcpy(user_name, buf, sizeof(user_name)); } else { if (remote_machine != NULL) { old_passwd = get_pass("Old SMB password:"******"Unable to get old password.\n"); exit(1); } } if (!(local_flags & LOCAL_SET_PASSWORD)) { /* * If we are trying to enable a user, first we need to find out * if they are using a modern version of the smbpasswd file that * disables a user by just writing a flag into the file. If so * then we can re-enable a user without prompting for a new * password. If not (ie. they have a no stored password in the * smbpasswd file) then we need to prompt for a new password. */ if(local_flags & LOCAL_ENABLE_USER) { struct samu *sampass = NULL; sampass = samu_new( NULL ); if (!sampass) { fprintf(stderr, "talloc fail for struct samu.\n"); exit(1); } if (!pdb_getsampwnam(sampass, user_name)) { fprintf(stderr, "Failed to find user %s in passdb backend.\n", user_name ); exit(1); } if(pdb_get_nt_passwd(sampass) == NULL) { local_flags |= LOCAL_SET_PASSWORD; } TALLOC_FREE(sampass); } } if((local_flags & LOCAL_SET_PASSWORD) && (new_passwd == NULL)) { new_passwd = prompt_for_new_password(stdin_passwd_get); if(!new_passwd) { fprintf(stderr, "Unable to get new password.\n"); exit(1); } } } if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags))) { result = 1; goto done; } if(remote_machine) { printf("Password changed for user %s on %s.\n", user_name, remote_machine ); } else if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) { struct samu *sampass = NULL; sampass = samu_new( NULL ); if (!sampass) { fprintf(stderr, "talloc fail for struct samu.\n"); exit(1); } if (!pdb_getsampwnam(sampass, user_name)) { fprintf(stderr, "Failed to find user %s in passdb backend.\n", user_name ); exit(1); } printf("Password changed for user %s.", user_name ); if(pdb_get_acct_ctrl(sampass)&ACB_DISABLED) { printf(" User has disabled flag set."); } if(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) { printf(" User has no password flag set."); } printf("\n"); TALLOC_FREE(sampass); } done: SAFE_FREE(old_passwd); SAFE_FREE(new_passwd); return result; }
static int process_nonroot(int local_flags) { struct passwd *pwd = NULL; int result = 0; char *old_pw = NULL; char *new_pw = NULL; if (local_flags & ~(LOCAL_AM_ROOT | LOCAL_SET_PASSWORD)) { /* Extra flags that we can't honor non-root */ usage(); } if (!user_name[0]) { pwd = getpwuid_alloc(talloc_tos(), getuid()); if (pwd) { fstrcpy(user_name,pwd->pw_name); TALLOC_FREE(pwd); } else { fprintf(stderr, "smbpasswd: cannot lookup user name for uid %u\n", (unsigned int)getuid()); exit(1); } } /* * A non-root user is always setting a password * via a remote machine (even if that machine is * localhost). */ load_interfaces(); /* Delayed from main() */ if (remote_machine == NULL) { remote_machine = "127.0.0.1"; } if (remote_machine != NULL) { old_pw = get_pass("Old SMB password:"******"Unable to get old password.\n"); exit(1); } } if (!new_passwd) { new_pw = prompt_for_new_password(stdin_passwd_get); } else new_pw = smb_xstrdup(new_passwd); if (!new_pw) { fprintf(stderr, "Unable to get new password.\n"); exit(1); } if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name, old_pw, new_pw, 0))) { result = 1; goto done; } printf("Password changed for user %s\n", user_name); done: SAFE_FREE(old_pw); SAFE_FREE(new_pw); return result; }
static NTSTATUS parse_dfs_path(connection_struct *conn, const char *pathname, bool allow_wcards, bool allow_broken_path, struct dfs_path *pdp, /* MUST BE TALLOCED */ bool *ppath_contains_wcard) { char *pathname_local; char *p,*temp; char *servicename; char *eos_ptr; NTSTATUS status = NT_STATUS_OK; char sepchar; ZERO_STRUCTP(pdp); /* * This is the only talloc we should need to do * on the struct dfs_path. All the pointers inside * it should point to offsets within this string. */ pathname_local = talloc_strdup(pdp, pathname); if (!pathname_local) { return NT_STATUS_NO_MEMORY; } /* Get a pointer to the terminating '\0' */ eos_ptr = &pathname_local[strlen(pathname_local)]; p = temp = pathname_local; pdp->posix_path = (lp_posix_pathnames() && *pathname == '/'); sepchar = pdp->posix_path ? '/' : '\\'; if (allow_broken_path && (*pathname != sepchar)) { DEBUG(10,("parse_dfs_path: path %s doesn't start with %c\n", pathname, sepchar )); /* * Possibly client sent a local path by mistake. * Try and convert to a local path. */ pdp->hostname = eos_ptr; /* "" */ pdp->servicename = eos_ptr; /* "" */ /* We've got no info about separators. */ pdp->posix_path = lp_posix_pathnames(); p = temp; DEBUG(10,("parse_dfs_path: trying to convert %s to a " "local path\n", temp)); goto local_path; } /* * Safe to use on talloc'ed string as it only shrinks. * It also doesn't affect the eos_ptr. */ trim_char(temp,sepchar,sepchar); DEBUG(10,("parse_dfs_path: temp = |%s| after trimming %c's\n", temp, sepchar)); /* Now tokenize. */ /* Parse out hostname. */ p = strchr_m(temp,sepchar); if(p == NULL) { DEBUG(10,("parse_dfs_path: can't parse hostname from path %s\n", temp)); /* * Possibly client sent a local path by mistake. * Try and convert to a local path. */ pdp->hostname = eos_ptr; /* "" */ pdp->servicename = eos_ptr; /* "" */ p = temp; DEBUG(10,("parse_dfs_path: trying to convert %s " "to a local path\n", temp)); goto local_path; } *p = '\0'; pdp->hostname = temp; DEBUG(10,("parse_dfs_path: hostname: %s\n",pdp->hostname)); /* Parse out servicename. */ servicename = p+1; p = strchr_m(servicename,sepchar); if (p) { *p = '\0'; } /* Is this really our servicename ? */ if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), SNUM(conn))) || (strequal(servicename, HOMES_NAME) && strequal(lp_servicename(talloc_tos(), SNUM(conn)), get_current_username()) )) ) { DEBUG(10,("parse_dfs_path: %s is not our servicename\n", servicename)); /* * Possibly client sent a local path by mistake. * Try and convert to a local path. */ pdp->hostname = eos_ptr; /* "" */ pdp->servicename = eos_ptr; /* "" */ /* Repair the path - replace the sepchar's we nulled out */ servicename--; *servicename = sepchar; if (p) { *p = sepchar; } p = temp; DEBUG(10,("parse_dfs_path: trying to convert %s " "to a local path\n", temp)); goto local_path; } pdp->servicename = servicename; DEBUG(10,("parse_dfs_path: servicename: %s\n",pdp->servicename)); if(p == NULL) { /* Client sent self referral \server\share. */ pdp->reqpath = eos_ptr; /* "" */ return NT_STATUS_OK; } p++; local_path: *ppath_contains_wcard = False; pdp->reqpath = p; /* Rest is reqpath. */ if (pdp->posix_path) { status = check_path_syntax_posix(pdp->reqpath); } else { if (allow_wcards) { status = check_path_syntax_wcard(pdp->reqpath, ppath_contains_wcard); } else { status = check_path_syntax(pdp->reqpath); } } if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("parse_dfs_path: '%s' failed with %s\n", p, nt_errstr(status) )); return status; } DEBUG(10,("parse_dfs_path: rest of the path: %s\n",pdp->reqpath)); return NT_STATUS_OK; }
NTSTATUS cli_dfs_get_referral(TALLOC_CTX *ctx, struct cli_state *cli, const char *path, struct client_dfs_referral **refs, size_t *num_refs, size_t *consumed) { unsigned int data_len = 0; unsigned int param_len = 0; uint16_t setup[1]; uint16_t recv_flags2; uint8_t *param = NULL; uint8_t *rdata = NULL; char *p; char *endp; size_t pathlen = 2*(strlen(path)+1); smb_ucs2_t *path_ucs; char *consumed_path = NULL; uint16_t consumed_ucs; uint16 num_referrals; struct client_dfs_referral *referrals = NULL; NTSTATUS status; *num_refs = 0; *refs = NULL; SSVAL(setup, 0, TRANSACT2_GET_DFS_REFERRAL); param = SMB_MALLOC_ARRAY(uint8_t, 2+pathlen+2); if (!param) { status = NT_STATUS_NO_MEMORY; goto out; } SSVAL(param, 0, 0x03); /* max referral level */ p = (char *)(¶m[2]); path_ucs = (smb_ucs2_t *)p; p += clistr_push(cli, p, path, pathlen, STR_TERMINATE); param_len = PTR_DIFF(p, param); status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, 0xffff, 0, 0, setup, 1, 0, param, param_len, 2, NULL, 0, cli->max_xmit, &recv_flags2, NULL, 0, NULL, /* rsetup */ NULL, 0, NULL, &rdata, 4, &data_len); if (!NT_STATUS_IS_OK(status)) { goto out; } endp = (char *)rdata + data_len; consumed_ucs = SVAL(rdata, 0); num_referrals = SVAL(rdata, 2); /* consumed_ucs is the number of bytes * of the UCS2 path consumed not counting any * terminating null. We need to convert * back to unix charset and count again * to get the number of bytes consumed from * the incoming path. */ errno = 0; if (pull_string_talloc(talloc_tos(), NULL, 0, &consumed_path, path_ucs, consumed_ucs, STR_UNICODE) == 0) { if (errno != 0) { status = map_nt_error_from_unix(errno); } else { status = NT_STATUS_INVALID_NETWORK_RESPONSE; } goto out; } if (consumed_path == NULL) { status = map_nt_error_from_unix(errno); goto out; } *consumed = strlen(consumed_path); if (num_referrals != 0) { uint16 ref_version; uint16 ref_size; int i; uint16 node_offset; referrals = talloc_array(ctx, struct client_dfs_referral, num_referrals); if (!referrals) { status = NT_STATUS_NO_MEMORY; goto out; } /* start at the referrals array */ p = (char *)rdata+8; for (i=0; i<num_referrals && p < endp; i++) { if (p + 18 > endp) { goto out; } ref_version = SVAL(p, 0); ref_size = SVAL(p, 2); node_offset = SVAL(p, 16); if (ref_version != 3) { p += ref_size; continue; } referrals[i].proximity = SVAL(p, 8); referrals[i].ttl = SVAL(p, 10); if (p + node_offset > endp) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto out; } clistr_pull_talloc(referrals, (const char *)rdata, recv_flags2, &referrals[i].dfspath, p+node_offset, PTR_DIFF(endp, p+node_offset), STR_TERMINATE|STR_UNICODE); if (!referrals[i].dfspath) { status = map_nt_error_from_unix(errno); goto out; } p += ref_size; } if (i < num_referrals) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto out; } }
int onefs_rename(vfs_handle_struct *handle, const struct smb_filename *smb_fname_src, const struct smb_filename *smb_fname_dst) { struct smb_filename *smb_fname_src_onefs = NULL; struct smb_filename *smb_fname_dst_onefs = NULL; NTSTATUS status; int saved_errno; int dir_fd = -1; int ret = -1; START_PROFILE(syscall_rename_at); if (!is_ntfs_stream_smb_fname(smb_fname_src) && !is_ntfs_stream_smb_fname(smb_fname_dst)) { ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst); goto done; } /* For now don't allow renames from or to the default stream. */ if (is_ntfs_default_stream_smb_fname(smb_fname_src) || is_ntfs_default_stream_smb_fname(smb_fname_dst)) { DEBUG(3, ("Unable to rename to/from a default stream: %s -> " "%s\n", smb_fname_str_dbg(smb_fname_src), smb_fname_str_dbg(smb_fname_dst))); errno = ENOSYS; goto done; } /* prep stream smb_filename structs. */ status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname_src, &smb_fname_src_onefs); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); goto done; } status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname_dst, &smb_fname_dst_onefs); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); goto done; } dir_fd = get_stream_dir_fd(handle->conn, smb_fname_src->base_name, NULL); if (dir_fd < -1) { goto done; } DEBUG(8, ("onefs_rename called for %s => %s\n", smb_fname_str_dbg(smb_fname_src_onefs), smb_fname_str_dbg(smb_fname_dst_onefs))); /* Handle rename of stream to default stream specially. */ if (smb_fname_dst_onefs->stream_name == NULL) { ret = enc_renameat(dir_fd, smb_fname_src_onefs->stream_name, ENC_DEFAULT, AT_FDCWD, smb_fname_dst_onefs->base_name, ENC_DEFAULT); } else { ret = enc_renameat(dir_fd, smb_fname_src_onefs->stream_name, ENC_DEFAULT, dir_fd, smb_fname_dst_onefs->stream_name, ENC_DEFAULT); } done: END_PROFILE(syscall_rename_at); TALLOC_FREE(smb_fname_src_onefs); TALLOC_FREE(smb_fname_dst_onefs); saved_errno = errno; if (dir_fd >= 0) { close(dir_fd); } errno = saved_errno; return ret; }
static int upgrade_v2_to_v3(struct db_record *rec, void *priv) { size_t prefix_len = strlen(SHARE_SECURITY_DB_KEY_PREFIX_STR); const char *servicename = NULL; char *c_servicename = NULL; char *newkey = NULL; bool *p_upgrade_ok = (bool *)priv; NTSTATUS status; TDB_DATA key; TDB_DATA value; key = dbwrap_record_get_key(rec); /* Is there space for a one character sharename ? */ if (key.dsize <= prefix_len+2) { return 0; } /* Does it start with the share key prefix ? */ if (memcmp(key.dptr, SHARE_SECURITY_DB_KEY_PREFIX_STR, prefix_len) != 0) { return 0; } /* Is it a null terminated string as a key ? */ if (key.dptr[key.dsize-1] != '\0') { return 0; } /* Bytes after the prefix are the sharename string. */ servicename = (char *)&key.dptr[prefix_len]; c_servicename = canonicalize_servicename(talloc_tos(), servicename); if (!c_servicename) { smb_panic("out of memory upgrading share security db from v2 -> v3"); } if (strcmp(servicename, c_servicename) == 0) { /* Old and new names match. No canonicalization needed. */ TALLOC_FREE(c_servicename); return 0; } /* Oops. Need to canonicalize name, delete old then store new. */ status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("upgrade_v2_to_v3: Failed to delete secdesc for " "%s: %s\n", (const char *)key.dptr, nt_errstr(status))); TALLOC_FREE(c_servicename); *p_upgrade_ok = false; return -1; } else { DEBUG(10, ("upgrade_v2_to_v3: deleted secdesc for " "%s\n", (const char *)key.dptr)); } if (!(newkey = talloc_asprintf(talloc_tos(), SHARE_SECURITY_DB_KEY_PREFIX_STR "%s", c_servicename))) { smb_panic("out of memory upgrading share security db from v2 -> v3"); } value = dbwrap_record_get_value(rec); status = dbwrap_store(share_db, string_term_tdb_data(newkey), value, TDB_REPLACE); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("upgrade_v2_to_v3: Failed to store secdesc for " "%s: %s\n", c_servicename, nt_errstr(status))); TALLOC_FREE(c_servicename); TALLOC_FREE(newkey); *p_upgrade_ok = false; return -1; } else { DEBUG(10, ("upgrade_v2_to_v3: stored secdesc for " "%s\n", newkey )); } TALLOC_FREE(newkey); TALLOC_FREE(c_servicename); return 0; }
static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username, const char *domain, const char *password, const DATA_BLOB initial_msg, const DATA_BLOB challenge_msg, TALLOC_CTX *mem_ctx, DATA_BLOB *auth_msg, uint8_t session_key[16]) { NTSTATUS status; struct auth_generic_state *auth_generic_state = NULL; DATA_BLOB reply, session_key_blob; status = auth_generic_client_prepare(mem_ctx, &auth_generic_state); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Could not start NTLMSSP client: %s\n", nt_errstr(status))); goto done; } status = auth_generic_set_username(auth_generic_state, username); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Could not set username: %s\n", nt_errstr(status))); goto done; } status = auth_generic_set_domain(auth_generic_state, domain); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Could not set domain: %s\n", nt_errstr(status))); goto done; } status = auth_generic_set_password(auth_generic_state, password); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Could not set password: %s\n", nt_errstr(status))); goto done; } if (initial_msg.length == 0) { gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SESSION_KEY); } status = auth_generic_client_start_by_name(auth_generic_state, "ntlmssp_resume_ccache"); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Could not start NTLMSSP resume mech: %s\n", nt_errstr(status))); goto done; } /* * We inject the inital NEGOTIATE message our caller used * in order to get the state machine into the correct possition. */ reply = data_blob_null; status = gensec_update(auth_generic_state->gensec_security, talloc_tos(), initial_msg, &reply); data_blob_free(&reply); if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { DEBUG(1, ("Failed to create initial message! [%s]\n", nt_errstr(status))); goto done; } /* Now we are ready to handle the server's actual response. */ status = gensec_update(auth_generic_state->gensec_security, mem_ctx, challenge_msg, &reply); if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) { DEBUG(1, ("We didn't get a response to the challenge! [%s]\n", nt_errstr(status))); data_blob_free(&reply); goto done; } status = gensec_session_key(auth_generic_state->gensec_security, talloc_tos(), &session_key_blob); if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) { DEBUG(1, ("We didn't get the session key we requested! [%s]\n", nt_errstr(status))); data_blob_free(&reply); goto done; } if (session_key_blob.length != 16) { DEBUG(1, ("invalid session key length %d\n", (int)session_key_blob.length)); data_blob_free(&reply); goto done; } memcpy(session_key, session_key_blob.data, 16); data_blob_free(&session_key_blob); *auth_msg = reply; status = NT_STATUS_OK; done: TALLOC_FREE(auth_generic_state); return status; }
static NTSTATUS inherit_new_acl(vfs_handle_struct *handle, const char *fname, files_struct *fsp, bool container) { TALLOC_CTX *ctx = talloc_tos(); NTSTATUS status; struct security_descriptor *parent_desc = NULL; struct security_descriptor *psd = NULL; DATA_BLOB blob; size_t size; char *parent_name; if (!parent_dirname_talloc(ctx, fname, &parent_name, NULL)) { return NT_STATUS_NO_MEMORY; } DEBUG(10,("inherit_new_acl: check directory %s\n", parent_name)); status = get_nt_acl_tdb_internal(handle, NULL, parent_name, (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION), &parent_desc); if (NT_STATUS_IS_OK(status)) { /* Create an inherited descriptor from the parent. */ if (DEBUGLEVEL >= 10) { DEBUG(10,("inherit_new_acl: parent acl is:\n")); NDR_PRINT_DEBUG(security_descriptor, parent_desc); } status = se_create_child_secdesc(ctx, &psd, &size, parent_desc, &handle->conn->server_info->ptok->user_sids[PRIMARY_USER_SID_INDEX], &handle->conn->server_info->ptok->user_sids[PRIMARY_GROUP_SID_INDEX], container); if (!NT_STATUS_IS_OK(status)) { return status; } if (DEBUGLEVEL >= 10) { DEBUG(10,("inherit_new_acl: child acl is:\n")); NDR_PRINT_DEBUG(security_descriptor, psd); } } else { DEBUG(10,("inherit_new_acl: directory %s failed " "to get acl %s\n", parent_name, nt_errstr(status) )); } if (!psd || psd->dacl == NULL) { SMB_STRUCT_STAT sbuf; int ret; TALLOC_FREE(psd); if (fsp && !fsp->is_directory && fsp->fh->fd != -1) { ret = SMB_VFS_FSTAT(fsp, &sbuf); } else { if (fsp && fsp->posix_open) { ret = SMB_VFS_LSTAT(handle->conn,fname, &sbuf); } else { ret = SMB_VFS_STAT(handle->conn,fname, &sbuf); } } if (ret == -1) { return map_nt_error_from_unix(errno); } psd = default_file_sd(ctx, &sbuf); if (!psd) { return NT_STATUS_NO_MEMORY; } if (DEBUGLEVEL >= 10) { DEBUG(10,("inherit_new_acl: default acl is:\n")); NDR_PRINT_DEBUG(security_descriptor, psd); } } status = create_acl_blob(psd, &blob); if (!NT_STATUS_IS_OK(status)) { return status; } if (fsp) { return store_acl_blob_fsp(handle, fsp, &blob); } else { return store_acl_blob_pathname(handle, fname, &blob); } }
NTSTATUS change_trust_account_password( const char *domain, const char *remote_machine) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct sockaddr_storage pdc_ss; fstring dc_name; struct cli_state *cli = NULL; struct rpc_pipe_client *netlogon_pipe = NULL; DEBUG(5,("change_trust_account_password: Attempting to change trust account password in domain %s....\n", domain)); if (remote_machine == NULL || !strcmp(remote_machine, "*")) { /* Use the PDC *only* for this */ if ( !get_pdc_ip(domain, &pdc_ss) ) { DEBUG(0,("Can't get IP for PDC for domain %s\n", domain)); goto failed; } if ( !name_status_find( domain, 0x1b, 0x20, &pdc_ss, dc_name) ) goto failed; } else { /* supoport old deprecated "smbpasswd -j DOMAIN -r MACHINE" behavior */ fstrcpy( dc_name, remote_machine ); } /* if this next call fails, then give up. We can't do password changes on BDC's --jerry */ if (!NT_STATUS_IS_OK(cli_full_connection(&cli, global_myname(), dc_name, NULL, 0, "IPC$", "IPC", "", "", "", 0, Undefined, NULL))) { DEBUG(0,("modify_trust_password: Connection to %s failed!\n", dc_name)); nt_status = NT_STATUS_UNSUCCESSFUL; goto failed; } /* * Ok - we have an anonymous connection to the IPC$ share. * Now start the NT Domain stuff :-). */ /* Shouldn't we open this with schannel ? JRA. */ nt_status = cli_rpc_pipe_open_noauth( cli, &ndr_table_netlogon.syntax_id, &netlogon_pipe); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("modify_trust_password: unable to open the domain client session to machine %s. Error was : %s.\n", dc_name, nt_errstr(nt_status))); cli_shutdown(cli); cli = NULL; goto failed; } nt_status = trust_pw_find_change_and_store_it( netlogon_pipe, netlogon_pipe, domain); cli_shutdown(cli); cli = NULL; failed: if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("%s : change_trust_account_password: Failed to change password for domain %s.\n", current_timestring(talloc_tos(), False), domain)); } else DEBUG(5,("change_trust_account_password: sucess!\n")); return nt_status; }
int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern, bool is_case_sensitive) { smb_ucs2_t *p = NULL; smb_ucs2_t *s = NULL; int ret; size_t count, i; struct max_n *max_n = NULL; struct max_n *max_n_free = NULL; struct max_n one_max_n; size_t converted_size; if (ISDOTDOT(string)) { string = "."; } if (strpbrk(pattern, "<>*?\"") == NULL) { /* this is not just an optimisation - it is essential for LANMAN1 correctness */ if (is_case_sensitive) { return strcmp(pattern, string); } else { return strcasecmp_m(pattern, string); } } if (!push_ucs2_talloc(talloc_tos(), &p, pattern, &converted_size)) { return -1; } if (!push_ucs2_talloc(talloc_tos(), &s, string, &converted_size)) { TALLOC_FREE(p); return -1; } if (translate_pattern) { /* for older negotiated protocols it is possible to translate the pattern to produce a "new style" pattern that exactly matches w2k behaviour */ for (i=0;p[i];i++) { if (p[i] == UCS2_CHAR('?')) { p[i] = UCS2_CHAR('>'); } else if (p[i] == UCS2_CHAR('.') && (p[i+1] == UCS2_CHAR('?') || p[i+1] == UCS2_CHAR('*') || p[i+1] == 0)) { p[i] = UCS2_CHAR('"'); } else if (p[i] == UCS2_CHAR('*') && p[i+1] == UCS2_CHAR('.')) { p[i] = UCS2_CHAR('<'); } } } for (count=i=0;p[i];i++) { if (p[i] == UCS2_CHAR('*') || p[i] == UCS2_CHAR('<')) count++; } if (count != 0) { if (count == 1) { /* * We're doing this a LOT, so save the effort to allocate */ ZERO_STRUCT(one_max_n); max_n = &one_max_n; } else { max_n = SMB_CALLOC_ARRAY(struct max_n, count); if (!max_n) { TALLOC_FREE(p); TALLOC_FREE(s); return -1; } max_n_free = max_n; } } ret = ms_fnmatch_core(p, s, max_n, strrchr_w(s, UCS2_CHAR('.')), is_case_sensitive); SAFE_FREE(max_n_free); TALLOC_FREE(p); TALLOC_FREE(s); return ret; }
static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx, struct samu *sampass, const struct auth_usersupplied_info *user_info) { uint32 acct_ctrl = pdb_get_acct_ctrl(sampass); char *workstation_list; time_t kickoff_time; DEBUG(4,("sam_account_ok: Checking SMB password for user %s\n",pdb_get_username(sampass))); /* Quit if the account was disabled. */ if (acct_ctrl & ACB_DISABLED) { DEBUG(1,("sam_account_ok: Account for user '%s' was disabled.\n", pdb_get_username(sampass))); return NT_STATUS_ACCOUNT_DISABLED; } /* Quit if the account was locked out. */ if (acct_ctrl & ACB_AUTOLOCK) { DEBUG(1,("sam_account_ok: Account for user %s was locked out.\n", pdb_get_username(sampass))); return NT_STATUS_ACCOUNT_LOCKED_OUT; } /* Quit if the account is not allowed to logon at this time. */ if (! logon_hours_ok(sampass)) { return NT_STATUS_INVALID_LOGON_HOURS; } /* Test account expire time */ kickoff_time = pdb_get_kickoff_time(sampass); if (kickoff_time != 0 && time(NULL) > kickoff_time) { DEBUG(1,("sam_account_ok: Account for user '%s' has expired.\n", pdb_get_username(sampass))); DEBUG(3,("sam_account_ok: Account expired at '%ld' unix time.\n", (long)kickoff_time)); return NT_STATUS_ACCOUNT_EXPIRED; } if (!(pdb_get_acct_ctrl(sampass) & ACB_PWNOEXP) && !(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ)) { time_t must_change_time = pdb_get_pass_must_change_time(sampass); time_t last_set_time = pdb_get_pass_last_set_time(sampass); /* check for immediate expiry "must change at next logon" * for a user account. */ if (((acct_ctrl & (ACB_WSTRUST|ACB_SVRTRUST)) == 0) && (last_set_time == 0)) { DEBUG(1,("sam_account_ok: Account for user '%s' password must change!\n", pdb_get_username(sampass))); return NT_STATUS_PASSWORD_MUST_CHANGE; } /* check for expired password */ if (must_change_time < time(NULL) && must_change_time != 0) { DEBUG(1,("sam_account_ok: Account for user '%s' password expired!\n", pdb_get_username(sampass))); DEBUG(1,("sam_account_ok: Password expired at '%s' (%ld) unix time.\n", http_timestring(talloc_tos(), must_change_time), (long)must_change_time)); return NT_STATUS_PASSWORD_EXPIRED; } } /* Test workstation. Workstation list is comma separated. */ workstation_list = talloc_strdup(mem_ctx, pdb_get_workstations(sampass)); if (!workstation_list) return NT_STATUS_NO_MEMORY; if (*workstation_list) { bool invalid_ws = True; char *tok = NULL; const char *s = workstation_list; char *machine_name = talloc_asprintf(mem_ctx, "%s$", user_info->workstation_name); if (machine_name == NULL) return NT_STATUS_NO_MEMORY; while (next_token_talloc(mem_ctx, &s, &tok, ",")) { DEBUG(10,("sam_account_ok: checking for workstation match %s and %s\n", tok, user_info->workstation_name)); if(strequal(tok, user_info->workstation_name)) { invalid_ws = False; break; } if (tok[0] == '+') { DEBUG(10,("sam_account_ok: checking for workstation %s in group: %s\n", machine_name, tok + 1)); if (user_in_group(machine_name, tok + 1)) { invalid_ws = False; break; } } TALLOC_FREE(tok); } TALLOC_FREE(tok); TALLOC_FREE(machine_name); if (invalid_ws) return NT_STATUS_INVALID_WORKSTATION; } if (acct_ctrl & ACB_DOMTRUST) { DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", pdb_get_username(sampass))); return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT; } if (acct_ctrl & ACB_SVRTRUST) { if (!(user_info->logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) { DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", pdb_get_username(sampass))); return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT; } } if (acct_ctrl & ACB_WSTRUST) { if (!(user_info->logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) { DEBUG(2,("sam_account_ok: Wksta trust account %s denied by server\n", pdb_get_username(sampass))); return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT; } } return NT_STATUS_OK; }
char *sid_string_tos(const struct dom_sid *sid) { return sid_string_talloc(talloc_tos(), sid); }
static void print_share_mode(const struct share_mode_entry *e, const char *sharepath, const char *fname, void *dummy) { char *utf8_fname; char *utf8_sharepath; int deny_mode; size_t converted_size; if (!is_valid_share_mode_entry(e)) { return; } deny_mode = map_share_mode_to_deny_mode(e->share_access, e->private_options); printf("<tr><td>%s</td>",_(mapPid2Machine(e->pid))); printf("<td>%u</td>",(unsigned int)e->uid); printf("<td>"); switch ((deny_mode>>4)&0xF) { case DENY_NONE: printf("DENY_NONE"); break; case DENY_ALL: printf("DENY_ALL "); break; case DENY_DOS: printf("DENY_DOS "); break; case DENY_FCB: printf("DENY_FCB "); break; case DENY_READ: printf("DENY_READ "); break; case DENY_WRITE:printf("DENY_WRITE "); break; } printf("</td>"); printf("<td>"); if (e->access_mask & (FILE_READ_DATA|FILE_WRITE_DATA)) { printf("%s", _("RDWR ")); } else if (e->access_mask & FILE_WRITE_DATA) { printf("%s", _("WRONLY ")); } else { printf("%s", _("RDONLY ")); } printf("</td>"); printf("<td>"); if((e->op_type & (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) == (EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) printf("EXCLUSIVE+BATCH "); else if (e->op_type & EXCLUSIVE_OPLOCK) printf("EXCLUSIVE "); else if (e->op_type & BATCH_OPLOCK) printf("BATCH "); else if (e->op_type & LEVEL_II_OPLOCK) printf("LEVEL_II "); else printf("NONE "); printf("</td>"); push_utf8_talloc(talloc_tos(), &utf8_fname, fname, &converted_size); push_utf8_talloc(talloc_tos(), &utf8_sharepath, sharepath, &converted_size); printf("<td>%s</td><td>%s</td><td>%s</td></tr>\n", utf8_sharepath,utf8_fname,tstring(talloc_tos(),e->time.tv_sec)); TALLOC_FREE(utf8_fname); }
DATA_BLOB spnego_gen_negTokenInit(TALLOC_CTX *ctx, const char *OIDs[], DATA_BLOB *psecblob, const char *principal) { int i; ASN1_DATA *data; DATA_BLOB ret = data_blob_null; data = asn1_init(talloc_tos()); if (data == NULL) { return data_blob_null; } if (!asn1_push_tag(data,ASN1_APPLICATION(0))) goto err; if (!asn1_write_OID(data,OID_SPNEGO)) goto err; if (!asn1_push_tag(data,ASN1_CONTEXT(0))) goto err; if (!asn1_push_tag(data,ASN1_SEQUENCE(0))) goto err; if (!asn1_push_tag(data,ASN1_CONTEXT(0))) goto err; if (!asn1_push_tag(data,ASN1_SEQUENCE(0))) goto err; for (i=0; OIDs[i]; i++) { if (!asn1_write_OID(data,OIDs[i])) goto err; } if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; if (psecblob && psecblob->length && psecblob->data) { if (!asn1_push_tag(data, ASN1_CONTEXT(2))) goto err; if (!asn1_write_OctetString(data,psecblob->data, psecblob->length)) goto err; if (!asn1_pop_tag(data)) goto err; } if (principal) { if (!asn1_push_tag(data, ASN1_CONTEXT(3))) goto err; if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err; if (!asn1_push_tag(data, ASN1_CONTEXT(0))) goto err; if (!asn1_write_GeneralString(data,principal)) goto err; if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; } if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; if (!asn1_extract_blob(data, ctx, &ret)) { goto err; } err: if (asn1_has_error(data)) { DEBUG(1, ("Failed to build negTokenInit at offset %d\n", (int)asn1_current_ofs(data))); } asn1_free(data); return ret; }
struct byte_range_lock *do_lock(struct messaging_context *msg_ctx, files_struct *fsp, uint64_t smblctx, uint64_t count, uint64_t offset, enum brl_type lock_type, enum brl_flavour lock_flav, bool blocking_lock, NTSTATUS *perr, uint64_t *psmblctx, struct blocking_lock_record *blr) { struct byte_range_lock *br_lck = NULL; /* silently return ok on print files as we don't do locking there */ if (fsp->print_file) { *perr = NT_STATUS_OK; return NULL; } if (!fsp->can_lock) { *perr = fsp->is_directory ? NT_STATUS_INVALID_DEVICE_REQUEST : NT_STATUS_INVALID_HANDLE; return NULL; } if (!lp_locking(fsp->conn->params)) { *perr = NT_STATUS_OK; return NULL; } /* NOTE! 0 byte long ranges ARE allowed and should be stored */ DEBUG(10,("do_lock: lock flavour %s lock type %s start=%.0f len=%.0f " "blocking_lock=%s requested for %s file %s\n", lock_flav_name(lock_flav), lock_type_name(lock_type), (double)offset, (double)count, blocking_lock ? "true" : "false", fsp_fnum_dbg(fsp), fsp_str_dbg(fsp))); br_lck = brl_get_locks(talloc_tos(), fsp); if (!br_lck) { *perr = NT_STATUS_NO_MEMORY; return NULL; } *perr = brl_lock(msg_ctx, br_lck, smblctx, messaging_server_id(fsp->conn->sconn->msg_ctx), offset, count, lock_type, lock_flav, blocking_lock, psmblctx, blr); DEBUG(10, ("do_lock: returning status=%s\n", nt_errstr(*perr))); increment_current_lock_count(fsp, lock_flav); return br_lck; }
static ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data, size_t n, bool *is_data_outstanding) { uint32 pdu_remaining = 0; ssize_t data_returned = 0; if (!p) { DEBUG(0,("read_from_pipe: pipe not open\n")); return -1; } DEBUG(6,(" name: %s len: %u\n", get_pipe_name_from_syntax(talloc_tos(), &p->syntax), (unsigned int)n)); /* * We cannot return more than one PDU length per * read request. */ /* * This condition should result in the connection being closed. * Netapp filers seem to set it to 0xffff which results in domain * authentications failing. Just ignore it so things work. */ if(n > RPC_MAX_PDU_FRAG_LEN) { DEBUG(5,("read_from_pipe: too large read (%u) requested on " "pipe %s. We can only service %d sized reads.\n", (unsigned int)n, get_pipe_name_from_syntax(talloc_tos(), &p->syntax), RPC_MAX_PDU_FRAG_LEN )); n = RPC_MAX_PDU_FRAG_LEN; } /* * Determine if there is still data to send in the * pipe PDU buffer. Always send this first. Never * send more than is left in the current PDU. The * client should send a new read request for a new * PDU. */ pdu_remaining = p->out_data.frag.length - p->out_data.current_pdu_sent; if (pdu_remaining > 0) { data_returned = (ssize_t)MIN(n, pdu_remaining); DEBUG(10,("read_from_pipe: %s: current_pdu_len = %u, " "current_pdu_sent = %u returning %d bytes.\n", get_pipe_name_from_syntax(talloc_tos(), &p->syntax), (unsigned int)p->out_data.frag.length, (unsigned int)p->out_data.current_pdu_sent, (int)data_returned)); memcpy(data, p->out_data.frag.data + p->out_data.current_pdu_sent, data_returned); p->out_data.current_pdu_sent += (uint32)data_returned; goto out; } /* * At this point p->current_pdu_len == p->current_pdu_sent (which * may of course be zero if this is the first return fragment. */ DEBUG(10,("read_from_pipe: %s: fault_state = %d : data_sent_length " "= %u, p->out_data.rdata.length = %u.\n", get_pipe_name_from_syntax(talloc_tos(), &p->syntax), (int)p->fault_state, (unsigned int)p->out_data.data_sent_length, (unsigned int)p->out_data.rdata.length)); if (p->out_data.data_sent_length >= p->out_data.rdata.length) { /* * We have sent all possible data, return 0. */ data_returned = 0; goto out; } /* * We need to create a new PDU from the data left in p->rdata. * Create the header/data/footers. This also sets up the fields * p->current_pdu_len, p->current_pdu_sent, p->data_sent_length * and stores the outgoing PDU in p->current_pdu. */ if(!create_next_pdu(p)) { DEBUG(0,("read_from_pipe: %s: create_next_pdu failed.\n", get_pipe_name_from_syntax(talloc_tos(), &p->syntax))); return -1; } data_returned = MIN(n, p->out_data.frag.length); memcpy(data, p->out_data.frag.data, (size_t)data_returned); p->out_data.current_pdu_sent += (uint32)data_returned; out: (*is_data_outstanding) = p->out_data.frag.length > n; if (p->out_data.current_pdu_sent == p->out_data.frag.length) { /* We've returned everything in the out_data.frag * so we're done with this pdu. Free it and reset * current_pdu_sent. */ p->out_data.current_pdu_sent = 0; data_blob_free(&p->out_data.frag); if (p->out_data.data_sent_length >= p->out_data.rdata.length) { /* * We're completely finished with both outgoing and * incoming data streams. It's safe to free all * temporary data from this request. */ free_pipe_context(p); } } return data_returned; }
static NTSTATUS smbd_smb2_tree_connect(struct smbd_smb2_request *req, const char *in_path, uint8_t *out_share_type, uint32_t *out_share_flags, uint32_t *out_capabilities, uint32_t *out_maximal_access, uint32_t *out_tree_id) { struct smbXsrv_connection *conn = req->sconn->conn; const char *share = in_path; char *service = NULL; int snum = -1; struct smbXsrv_tcon *tcon; NTTIME now = timeval_to_nttime(&req->request_time); connection_struct *compat_conn = NULL; struct user_struct *compat_vuser = req->session->compat; NTSTATUS status; bool encryption_desired = req->session->encryption_desired; bool encryption_required = req->session->global->encryption_required; bool guest_session = false; if (strncmp(share, "\\\\", 2) == 0) { const char *p = strchr(share+2, '\\'); if (p) { share = p + 1; } } DEBUG(10,("smbd_smb2_tree_connect: path[%s] share[%s]\n", in_path, share)); service = talloc_strdup(talloc_tos(), share); if(!service) { return NT_STATUS_NO_MEMORY; } if (!strlower_m(service)) { DEBUG(2, ("strlower_m %s failed\n", service)); return NT_STATUS_INVALID_PARAMETER; } /* TODO: do more things... */ if (strequal(service,HOMES_NAME)) { if (compat_vuser->homes_snum == -1) { DEBUG(2, ("[homes] share not available for " "user %s because it was not found " "or created at session setup " "time\n", compat_vuser->session_info->unix_info->unix_name)); return NT_STATUS_BAD_NETWORK_NAME; } snum = compat_vuser->homes_snum; } else if ((compat_vuser->homes_snum != -1) && strequal(service, lp_servicename(talloc_tos(), compat_vuser->homes_snum))) { snum = compat_vuser->homes_snum; } else { snum = find_service(talloc_tos(), service, &service); if (!service) { return NT_STATUS_NO_MEMORY; } } if (snum < 0) { DEBUG(3,("smbd_smb2_tree_connect: couldn't find service %s\n", service)); return NT_STATUS_BAD_NETWORK_NAME; } if ((lp_smb_encrypt(snum) >= SMB_SIGNING_DESIRED) && (conn->smb2.client.capabilities & SMB2_CAP_ENCRYPTION)) { encryption_desired = true; } if (lp_smb_encrypt(snum) == SMB_SIGNING_REQUIRED) { encryption_desired = true; encryption_required = true; } if (security_session_user_level(compat_vuser->session_info, NULL) < SECURITY_USER) { guest_session = true; } if (guest_session && encryption_required) { DEBUG(1,("reject guest as encryption is required for service %s\n", service)); return NT_STATUS_ACCESS_DENIED; } if (!(conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) { if (encryption_required) { DEBUG(1,("reject tcon with dialect[0x%04X] " "as encryption is required for service %s\n", conn->smb2.server.dialect, service)); return NT_STATUS_ACCESS_DENIED; } } /* create a new tcon as child of the session */ status = smb2srv_tcon_create(req->session, now, &tcon); if (!NT_STATUS_IS_OK(status)) { return status; } tcon->encryption_desired = encryption_desired; tcon->global->encryption_required = encryption_required; compat_conn = make_connection_smb2(req->sconn, tcon, snum, req->session->compat, "???", &status); if (compat_conn == NULL) { TALLOC_FREE(tcon); return status; } tcon->global->share_name = lp_servicename(tcon->global, SNUM(compat_conn)); if (tcon->global->share_name == NULL) { conn_free(compat_conn); TALLOC_FREE(tcon); return NT_STATUS_NO_MEMORY; } tcon->global->session_global_id = req->session->global->session_global_id; tcon->compat = talloc_move(tcon, &compat_conn); tcon->status = NT_STATUS_OK; status = smbXsrv_tcon_update(tcon); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(tcon); return status; } if (IS_PRINT(tcon->compat)) { *out_share_type = SMB2_SHARE_TYPE_PRINT; } else if (IS_IPC(tcon->compat)) { *out_share_type = SMB2_SHARE_TYPE_PIPE; } else { *out_share_type = SMB2_SHARE_TYPE_DISK; } *out_share_flags = 0; if (lp_msdfs_root(SNUM(tcon->compat)) && lp_host_msdfs()) { *out_share_flags |= (SMB2_SHAREFLAG_DFS|SMB2_SHAREFLAG_DFS_ROOT); *out_capabilities = SMB2_SHARE_CAP_DFS; } else { *out_capabilities = 0; } switch(lp_csc_policy(SNUM(tcon->compat))) { case CSC_POLICY_MANUAL: break; case CSC_POLICY_DOCUMENTS: *out_share_flags |= SMB2_SHAREFLAG_AUTO_CACHING; break; case CSC_POLICY_PROGRAMS: *out_share_flags |= SMB2_SHAREFLAG_VDO_CACHING; break; case CSC_POLICY_DISABLE: *out_share_flags |= SMB2_SHAREFLAG_NO_CACHING; break; default: break; } if (lp_hideunreadable(SNUM(tcon->compat)) || lp_hideunwriteable_files(SNUM(tcon->compat))) { *out_share_flags |= SMB2_SHAREFLAG_ACCESS_BASED_DIRECTORY_ENUM; } if (encryption_desired) { *out_share_flags |= SMB2_SHAREFLAG_ENCRYPT_DATA; } *out_maximal_access = tcon->compat->share_access; *out_tree_id = tcon->global->tcon_wire_id; return NT_STATUS_OK; }
static int get_real_filename_full_scan(connection_struct *conn, const char *path, const char *name, bool mangled, TALLOC_CTX *mem_ctx, char **found_name) { struct smb_Dir *cur_dir; const char *dname = NULL; char *talloced = NULL; char *unmangled_name = NULL; long curpos; /* handle null paths */ if ((path == NULL) || (*path == 0)) { path = "."; } /* If we have a case-sensitive filesystem, it doesn't do us any * good to search for a name. If a case variation of the name was * there, then the original stat(2) would have found it. */ if (!mangled && !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) { errno = ENOENT; return -1; } /* * The incoming name can be mangled, and if we de-mangle it * here it will not compare correctly against the filename (name2) * read from the directory and then mangled by the name_to_8_3() * call. We need to mangle both names or neither. * (JRA). * * Fix for bug found by Dina Fine. If in case sensitive mode then * the mangle cache is no good (3 letter extension could be wrong * case - so don't demangle in this case - leave as mangled and * allow the mangling of the directory entry read (which is done * case insensitively) to match instead. This will lead to more * false positive matches but we fail completely without it. JRA. */ if (mangled && !conn->case_sensitive) { mangled = !mangle_lookup_name_from_8_3(talloc_tos(), name, &unmangled_name, conn->params); if (!mangled) { /* Name is now unmangled. */ name = unmangled_name; } } /* open the directory */ if (!(cur_dir = OpenDir(talloc_tos(), conn, path, NULL, 0))) { DEBUG(3,("scan dir didn't open dir [%s]\n",path)); TALLOC_FREE(unmangled_name); return -1; } /* now scan for matching names */ curpos = 0; while ((dname = ReadDirName(cur_dir, &curpos, NULL, &talloced))) { /* Is it dot or dot dot. */ if (ISDOT(dname) || ISDOTDOT(dname)) { TALLOC_FREE(talloced); continue; } /* * At this point dname is the unmangled name. * name is either mangled or not, depending on the state * of the "mangled" variable. JRA. */ /* * Check mangled name against mangled name, or unmangled name * against unmangled name. */ if ((mangled && mangled_equal(name,dname,conn->params)) || fname_equal(name, dname, conn->case_sensitive)) { /* we've found the file, change it's name and return */ *found_name = talloc_strdup(mem_ctx, dname); TALLOC_FREE(unmangled_name); TALLOC_FREE(cur_dir); if (!*found_name) { errno = ENOMEM; TALLOC_FREE(talloced); return -1; } TALLOC_FREE(talloced); return 0; } TALLOC_FREE(talloced); } TALLOC_FREE(unmangled_name); TALLOC_FREE(cur_dir); errno = ENOENT; return -1; }
static bool test_plaintext(enum ntlm_break break_which) { NTSTATUS nt_status; uint32 flags = 0; DATA_BLOB nt_response = data_blob_null; DATA_BLOB lm_response = data_blob_null; char *password; smb_ucs2_t *nt_response_ucs2; size_t converted_size; uchar user_session_key[16]; uchar lm_key[16]; static const uchar zeros[8] = { 0, }; DATA_BLOB chall = data_blob(zeros, sizeof(zeros)); char *error_string; ZERO_STRUCT(user_session_key); flags |= WBFLAG_PAM_LMKEY; flags |= WBFLAG_PAM_USER_SESSION_KEY; if (!push_ucs2_talloc(talloc_tos(), &nt_response_ucs2, opt_password, &converted_size)) { DEBUG(0, ("push_ucs2_talloc failed!\n")); exit(1); } nt_response.data = (unsigned char *)nt_response_ucs2; nt_response.length = strlen_w(nt_response_ucs2)*sizeof(smb_ucs2_t); if ((password = strupper_talloc(talloc_tos(), opt_password)) == NULL) { DEBUG(0, ("strupper_talloc() failed!\n")); exit(1); } if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_DOS, password, strlen(password)+1, &lm_response.data, &lm_response.length)) { DEBUG(0, ("convert_string_talloc failed!\n")); exit(1); } TALLOC_FREE(password); switch (break_which) { case BREAK_NONE: break; case BREAK_LM: lm_response.data[0]++; break; case BREAK_NT: nt_response.data[0]++; break; case NO_LM: TALLOC_FREE(lm_response.data); lm_response.length = 0; break; case NO_NT: TALLOC_FREE(nt_response.data); nt_response.length = 0; break; } nt_status = contact_winbind_auth_crap(opt_username, opt_domain, opt_workstation, &chall, &lm_response, &nt_response, flags, lm_key, user_session_key, &error_string, NULL); TALLOC_FREE(nt_response.data); TALLOC_FREE(lm_response.data); data_blob_free(&chall); if (!NT_STATUS_IS_OK(nt_status)) { d_printf("%s (0x%x)\n", error_string, NT_STATUS_V(nt_status)); SAFE_FREE(error_string); return break_which == BREAK_NT; } return break_which != BREAK_NT; }
static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp, enum file_close_type close_type) { struct server_id self = messaging_server_id(fsp->conn->sconn->msg_ctx); struct share_mode_lock *lck = NULL; bool delete_dir = False; NTSTATUS status = NT_STATUS_OK; NTSTATUS status1 = NT_STATUS_OK; const struct security_token *del_nt_token = NULL; const struct security_unix_token *del_token = NULL; NTSTATUS notify_status; if (fsp->conn->sconn->using_smb2) { notify_status = STATUS_NOTIFY_CLEANUP; } else { notify_status = NT_STATUS_OK; } /* * NT can set delete_on_close of the last open * reference to a directory also. */ lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id); if (lck == NULL) { DEBUG(0, ("close_directory: Could not get share mode lock for " "%s\n", fsp_str_dbg(fsp))); return NT_STATUS_INVALID_PARAMETER; } if (fsp->initial_delete_on_close) { bool became_user = False; /* Initial delete on close was set - for * directories we don't care if anyone else * wrote a real delete on close. */ if (get_current_vuid(fsp->conn) != fsp->vuid) { become_user(fsp->conn, fsp->vuid); became_user = True; } send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx, fsp->fsp_name->base_name); set_delete_on_close_lck(fsp, lck, get_current_nttok(fsp->conn), get_current_utok(fsp->conn)); fsp->delete_on_close = true; if (became_user) { unbecome_user(); } } delete_dir = get_delete_on_close_token(lck, fsp->name_hash, &del_nt_token, &del_token); if (delete_dir) { int i; /* See if others still have the dir open. If this is the * case, then don't delete. If all opens are POSIX delete now. */ for (i=0; i<lck->data->num_share_modes; i++) { struct share_mode_entry *e = &lck->data->share_modes[i]; if (is_valid_share_mode_entry(e) && e->name_hash == fsp->name_hash) { if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) && (e->flags & SHARE_MODE_FLAG_POSIX_OPEN)) { continue; } if (serverid_equal(&self, &e->pid) && (e->share_file_id == fsp->fh->gen_id)) { continue; } if (share_mode_stale_pid(lck->data, i)) { continue; } delete_dir = False; break; } } } if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) && delete_dir) { /* Become the user who requested the delete. */ if (!push_sec_ctx()) { smb_panic("close_directory: failed to push sec_ctx.\n"); } set_sec_ctx(del_token->uid, del_token->gid, del_token->ngroups, del_token->groups, del_nt_token); if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_directory: Could not delete share entry for " "%s\n", fsp_str_dbg(fsp))); } TALLOC_FREE(lck); if ((fsp->conn->fs_capabilities & FILE_NAMED_STREAMS) && !is_ntfs_stream_smb_fname(fsp->fsp_name)) { status = delete_all_streams(fsp->conn, fsp->fsp_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(5, ("delete_all_streams failed: %s\n", nt_errstr(status))); return status; } } status = rmdir_internals(talloc_tos(), fsp); DEBUG(5,("close_directory: %s. Delete on close was set - " "deleting directory returned %s.\n", fsp_str_dbg(fsp), nt_errstr(status))); /* unbecome user. */ pop_sec_ctx(); /* * Ensure we remove any change notify requests that would * now fail as the directory has been deleted. */ if (NT_STATUS_IS_OK(status)) { notify_status = NT_STATUS_DELETE_PENDING; } } else { if (!del_share_mode(lck, fsp)) { DEBUG(0, ("close_directory: Could not delete share entry for " "%s\n", fsp_str_dbg(fsp))); } TALLOC_FREE(lck); } remove_pending_change_notify_requests_by_fid(fsp, notify_status); status1 = fd_close(fsp); if (!NT_STATUS_IS_OK(status1)) { DEBUG(0, ("Could not close dir! fname=%s, fd=%d, err=%d=%s\n", fsp_str_dbg(fsp), fsp->fh->fd, errno, strerror(errno))); } /* * Do the code common to files and directories. */ close_filestruct(fsp); file_free(req, fsp); if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(status1)) { status = status1; } return status; }
void process_blocking_lock_queue(struct smbd_server_connection *sconn) { struct timeval tv_curr = timeval_current(); struct blocking_lock_record *blr, *next = NULL; if (sconn->using_smb2) { process_blocking_lock_queue_smb2(sconn, tv_curr); return; } /* * Go through the queue and see if we can get any of the locks. */ for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) { next = blr->next; /* * Go through the remaining locks and try and obtain them. * The call returns True if all locks were obtained successfully * and False if we still need to wait. */ DEBUG(10, ("Processing BLR = %p\n", blr)); /* We use set_current_service so connections with * pending locks are not marked as idle. */ set_current_service(blr->fsp->conn, SVAL(blr->req->inbuf,smb_flg), false); if(blocking_lock_record_process(blr)) { struct byte_range_lock *br_lck = brl_get_locks( talloc_tos(), blr->fsp); DEBUG(10, ("BLR_process returned true: cancelling and " "removing lock. BLR = %p\n", blr)); if (br_lck) { brl_lock_cancel(br_lck, blr->smblctx, sconn_server_id(sconn), blr->offset, blr->count, blr->lock_flav, blr); TALLOC_FREE(br_lck); } DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr); TALLOC_FREE(blr); continue; } /* * We couldn't get the locks for this record on the list. * If the time has expired, return a lock error. */ if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) { struct byte_range_lock *br_lck = brl_get_locks( talloc_tos(), blr->fsp); DEBUG(10, ("Lock timed out! BLR = %p\n", blr)); /* * Lock expired - throw away all previously * obtained locks and return lock error. */ if (br_lck) { DEBUG(5,("process_blocking_lock_queue: " "pending lock fnum = %d for file %s " "timed out.\n", blr->fsp->fnum, fsp_str_dbg(blr->fsp))); brl_lock_cancel(br_lck, blr->smblctx, sconn_server_id(sconn), blr->offset, blr->count, blr->lock_flav, blr); TALLOC_FREE(br_lck); } blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr); TALLOC_FREE(blr); } } recalc_brl_timeout(sconn); }