Example #1
0
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;
}
Example #2
0
/*
 * 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;
}
Example #3
0
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 jht@samba.org 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 <t.neumann@iku-ag.de>.
				 */
				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;
}
Example #4
0
/*
  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;
}
Example #5
0
/*
 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;
}
Example #6
0
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;
}
Example #7
0
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);
}
Example #10
0
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:",stdin_passwd_get);
			if(!old_passwd) {
				fprintf(stderr, "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;
}
Example #11
0
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:",stdin_passwd_get);
		if (old_pw == NULL) {
			fprintf(stderr, "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;
}
Example #12
0
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;
}
Example #13
0
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 *)(&param[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;
		}
	}
Example #14
0
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;
}
Example #15
0
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;
}
Example #17
0
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);
	}
}
Example #18
0
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;
}
Example #19
0
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;
}
Example #20
0
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;
}
Example #21
0
char *sid_string_tos(const struct dom_sid *sid)
{
	return sid_string_talloc(talloc_tos(), sid);
}
Example #22
0
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);
}
Example #23
0
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;
}
Example #24
0
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;
}
Example #25
0
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;
}
Example #26
0
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;
}
Example #27
0
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;
}
Example #28
0
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;
}
Example #29
0
File: close.c Project: GSam/samba
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;
}
Example #30
0
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);
}