Exemple #1
0
static SMBCSRV *
SMBC_server_internal(TALLOC_CTX *ctx,
            SMBCCTX *context,
            bool connect_if_not_found,
            const char *server,
            uint16_t port,
            const char *share,
            char **pp_workgroup,
            char **pp_username,
            char **pp_password,
	    bool *in_cache)
{
	SMBCSRV *srv=NULL;
	char *workgroup = NULL;
	struct cli_state *c = NULL;
	const char *server_n = server;
        int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0);
	uint32_t fs_attrs = 0;
        const char *username_used;
 	NTSTATUS status;
	char *newserver, *newshare;
	int flags = 0;
	struct smbXcli_tcon *tcon = NULL;
	int signing_state = SMB_SIGNING_DEFAULT;

	ZERO_STRUCT(c);
	*in_cache = false;

	if (server[0] == 0) {
		errno = EPERM;
		return NULL;
	}

        /* Look for a cached connection */
        srv = SMBC_find_server(ctx, context, server, share,
                               pp_workgroup, pp_username, pp_password);

        /*
         * If we found a connection and we're only allowed one share per
         * server...
         */
        if (srv &&
	    share != NULL && *share != '\0' &&
            smbc_getOptionOneSharePerServer(context)) {

                /*
                 * ... then if there's no current connection to the share,
                 * connect to it.  SMBC_find_server(), or rather the function
                 * pointed to by context->get_cached_srv_fn which
                 * was called by SMBC_find_server(), will have issued a tree
                 * disconnect if the requested share is not the same as the
                 * one that was already connected.
                 */

		/*
		 * Use srv->cli->desthost and srv->cli->share instead of
		 * server and share below to connect to the actual share,
		 * i.e., a normal share or a referred share from
		 * 'msdfs proxy' share.
		 */
                if (!cli_state_has_tcon(srv->cli)) {
                        /* Ensure we have accurate auth info */
			SMBC_call_auth_fn(ctx, context,
					  smbXcli_conn_remote_name(srv->cli->conn),
					  srv->cli->share,
                                          pp_workgroup,
                                          pp_username,
                                          pp_password);

			if (!*pp_workgroup || !*pp_username || !*pp_password) {
				errno = ENOMEM;
				cli_shutdown(srv->cli);
				srv->cli = NULL;
				smbc_getFunctionRemoveCachedServer(context)(context,
                                                                            srv);
				return NULL;
			}

			/*
			 * We don't need to renegotiate encryption
			 * here as the encryption context is not per
			 * tid.
			 */

			status = cli_tree_connect(srv->cli,
						  srv->cli->share,
						  "?????",
						  *pp_password,
						  strlen(*pp_password)+1);
			if (!NT_STATUS_IS_OK(status)) {
                                errno = map_errno_from_nt_status(status);
                                cli_shutdown(srv->cli);
				srv->cli = NULL;
                                smbc_getFunctionRemoveCachedServer(context)(context,
                                                                            srv);
                                srv = NULL;
                        }

                        /* Determine if this share supports case sensitivity */
                        if (is_ipc) {
                                DEBUG(4,
                                      ("IPC$ so ignore case sensitivity\n"));
                                status = NT_STATUS_OK;
                        } else {
                                status = cli_get_fs_attr_info(c, &fs_attrs);
                        }

                        if (!NT_STATUS_IS_OK(status)) {
                                DEBUG(4, ("Could not retrieve "
                                          "case sensitivity flag: %s.\n",
                                          nt_errstr(status)));

                                /*
                                 * We can't determine the case sensitivity of
                                 * the share. We have no choice but to use the
                                 * user-specified case sensitivity setting.
                                 */
                                if (smbc_getOptionCaseSensitive(context)) {
                                        cli_set_case_sensitive(c, True);
                                } else {
                                        cli_set_case_sensitive(c, False);
                                }
                        } else if (!is_ipc) {
                                DEBUG(4,
                                      ("Case sensitive: %s\n",
                                       (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                                        ? "True"
                                        : "False")));
                                cli_set_case_sensitive(
                                        c,
                                        (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                                         ? True
                                         : False));
                        }

                        /*
                         * Regenerate the dev value since it's based on both
                         * server and share
                         */
                        if (srv) {
				const char *remote_name =
					smbXcli_conn_remote_name(srv->cli->conn);

				srv->dev = (dev_t)(str_checksum(remote_name) ^
                                                   str_checksum(srv->cli->share));
                        }
                }
        }

        /* If we have a connection... */
        if (srv) {

                /* ... then we're done here.  Give 'em what they came for. */
		*in_cache = true;
                goto done;
        }

        /* If we're not asked to connect when a connection doesn't exist... */
        if (! connect_if_not_found) {
                /* ... then we're done here. */
                return NULL;
        }

	if (!*pp_workgroup || !*pp_username || !*pp_password) {
		errno = ENOMEM;
		return NULL;
	}

	DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server));

	DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));

	status = NT_STATUS_UNSUCCESSFUL;

	if (smbc_getOptionUseKerberos(context)) {
		flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
	}

	if (smbc_getOptionFallbackAfterKerberos(context)) {
		flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
	}

	if (smbc_getOptionUseCCache(context)) {
		flags |= CLI_FULL_CONNECTION_USE_CCACHE;
	}

	if (smbc_getOptionUseNTHash(context)) {
		flags |= CLI_FULL_CONNECTION_USE_NT_HASH;
	}

	if (context->internal->smb_encryption_level != SMBC_ENCRYPTLEVEL_NONE) {
		signing_state = SMB_SIGNING_REQUIRED;
	}

	if (port == 0) {
	        if (share == NULL || *share == '\0' || is_ipc) {
			/*
			 * Try 139 first for IPC$
			 */
			status = cli_connect_nb(server_n, NULL, NBT_SMB_PORT, 0x20,
					smbc_getNetbiosName(context),
					signing_state, flags, &c);
		}
	}

	if (!NT_STATUS_IS_OK(status)) {
		/*
		 * No IPC$ or 139 did not work
		 */
		status = cli_connect_nb(server_n, NULL, port, 0x20,
					smbc_getNetbiosName(context),
					signing_state, flags, &c);
	}

	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		return NULL;
	}

	cli_set_timeout(c, smbc_getTimeout(context));

	status = smbXcli_negprot(c->conn, c->timeout,
				 lp_client_min_protocol(),
				 lp_client_max_protocol());
	if (!NT_STATUS_IS_OK(status)) {
		cli_shutdown(c);
		errno = ETIMEDOUT;
		return NULL;
	}

	if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
		/* Ensure we ask for some initial credits. */
		smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS);
	}

        username_used = *pp_username;

	if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
					       *pp_password,
                                               strlen(*pp_password),
					       *pp_password,
                                               strlen(*pp_password),
					       *pp_workgroup))) {

                /* Failed.  Try an anonymous login, if allowed by flags. */
                username_used = "";

                if (smbc_getOptionNoAutoAnonymousLogin(context) ||
                    !NT_STATUS_IS_OK(cli_session_setup(c, username_used,
                                                       *pp_password, 1,
                                                       *pp_password, 0,
                                                       *pp_workgroup))) {

                        cli_shutdown(c);
                        errno = EPERM;
                        return NULL;
                }
	}

	DEBUG(4,(" session setup ok\n"));

	/* here's the fun part....to support 'msdfs proxy' shares
	   (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
	   here before trying to connect to the original share.
	   cli_check_msdfs_proxy() will fail if it is a normal share. */

	if (smbXcli_conn_dfs_supported(c->conn) &&
			cli_check_msdfs_proxy(ctx, c, share,
				&newserver, &newshare,
				/* FIXME: cli_check_msdfs_proxy() does
				   not support smbc_smb_encrypt_level type */
				context->internal->smb_encryption_level ?
					true : false,
				*pp_username,
				*pp_password,
				*pp_workgroup)) {
		cli_shutdown(c);
		srv = SMBC_server_internal(ctx, context, connect_if_not_found,
				newserver, port, newshare, pp_workgroup,
				pp_username, pp_password, in_cache);
		TALLOC_FREE(newserver);
		TALLOC_FREE(newshare);
		return srv;
	}

	/* must be a normal share */

	status = cli_tree_connect(c, share, "?????", *pp_password,
				  strlen(*pp_password)+1);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		cli_shutdown(c);
		return NULL;
	}

	DEBUG(4,(" tconx ok\n"));

	if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) {
		tcon = c->smb2.tcon;
	} else {
		tcon = c->smb1.tcon;
	}

        /* Determine if this share supports case sensitivity */
	if (is_ipc) {
                DEBUG(4, ("IPC$ so ignore case sensitivity\n"));
                status = NT_STATUS_OK;
        } else {
                status = cli_get_fs_attr_info(c, &fs_attrs);
        }

        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n",
                          nt_errstr(status)));

                /*
                 * We can't determine the case sensitivity of the share. We
                 * have no choice but to use the user-specified case
                 * sensitivity setting.
                 */
                if (smbc_getOptionCaseSensitive(context)) {
                        cli_set_case_sensitive(c, True);
                } else {
                        cli_set_case_sensitive(c, False);
                }
	} else if (!is_ipc) {
                DEBUG(4, ("Case sensitive: %s\n",
                          (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                           ? "True"
                           : "False")));
		smbXcli_tcon_set_fs_attributes(tcon, fs_attrs);
        }

	if (context->internal->smb_encryption_level) {
		/* Attempt UNIX smb encryption. */
		if (!NT_STATUS_IS_OK(cli_force_encryption(c,
                                                          username_used,
                                                          *pp_password,
                                                          *pp_workgroup))) {

			/*
			 * context->smb_encryption_level == 1
			 * means don't fail if encryption can't be negotiated,
			 * == 2 means fail if encryption can't be negotiated.
			 */

			DEBUG(4,(" SMB encrypt failed\n"));

			if (context->internal->smb_encryption_level == 2) {
	                        cli_shutdown(c);
				errno = EPERM;
				return NULL;
			}
		}
		DEBUG(4,(" SMB encrypt ok\n"));
	}

	/*
	 * Ok, we have got a nice connection
	 * Let's allocate a server structure.
	 */

	srv = SMB_MALLOC_P(SMBCSRV);
	if (!srv) {
		cli_shutdown(c);
		errno = ENOMEM;
		return NULL;
	}

	ZERO_STRUCTP(srv);
	DLIST_ADD(srv->cli, c);
	srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
        srv->no_pathinfo = False;
        srv->no_pathinfo2 = False;
	srv->no_pathinfo3 = False;
        srv->no_nt_session = False;

done:
	if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) {
		workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context));
	} else {
		workgroup = *pp_workgroup;
	}
	if(!workgroup) {
		if (c != NULL) {
			cli_shutdown(c);
		}
		SAFE_FREE(srv);
		return NULL;
	}

	/* set the credentials to make DFS work */
	smbc_set_credentials_with_fallback(context,
					   workgroup,
				    	   *pp_username,
				   	   *pp_password);

	return srv;
}
Exemple #2
0
static SMBCSRV *
SMBC_server_internal(TALLOC_CTX *ctx,
            SMBCCTX *context,
            bool connect_if_not_found,
            const char *server,
            const char *share,
            char **pp_workgroup,
            char **pp_username,
            char **pp_password,
	    bool *in_cache)
{
	SMBCSRV *srv=NULL;
	char *workgroup = NULL;
	struct cli_state *c;
	struct nmb_name called, calling;
	const char *server_n = server;
	struct sockaddr_storage ss;
	int tried_reverse = 0;
        int port_try_first;
        int port_try_next;
        int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0);
	uint32 fs_attrs = 0;
        const char *username_used;
 	NTSTATUS status;
	char *newserver, *newshare;
	
	zero_sockaddr(&ss);
	ZERO_STRUCT(c);
	*in_cache = false;

	if (server[0] == 0) {
		errno = EPERM;
		return NULL;
	}
	
        /* Look for a cached connection */
        srv = SMBC_find_server(ctx, context, server, share,
                               pp_workgroup, pp_username, pp_password);

        /*
         * If we found a connection and we're only allowed one share per
         * server...
         */
        if (srv &&
            *share != '\0' &&
            smbc_getOptionOneSharePerServer(context)) {
			
                /*
                 * ... then if there's no current connection to the share,
                 * connect to it.  SMBC_find_server(), or rather the function
                 * pointed to by context->get_cached_srv_fn which
                 * was called by SMBC_find_server(), will have issued a tree
                 * disconnect if the requested share is not the same as the
                 * one that was already connected.
                 */

		/*
		 * Use srv->cli->desthost and srv->cli->share instead of
		 * server and share below to connect to the actual share,
		 * i.e., a normal share or a referred share from
		 * 'msdfs proxy' share.
		 */
                if (srv->cli->cnum == (uint16) -1) {
                        /* Ensure we have accurate auth info */
			SMBC_call_auth_fn(ctx, context,
					  srv->cli->desthost,
					  srv->cli->share,
                                          pp_workgroup,
                                          pp_username,
                                          pp_password);

			if (!*pp_workgroup || !*pp_username || !*pp_password) {
				errno = ENOMEM;
				cli_shutdown(srv->cli);
				srv->cli = NULL;
				smbc_getFunctionRemoveCachedServer(context)(context,
                                                                            srv);
				return NULL;
			}

			/*
			 * We don't need to renegotiate encryption
			 * here as the encryption context is not per
			 * tid.
			 */

			status = cli_tcon_andx(srv->cli, srv->cli->share, "?????",
					       *pp_password,
					       strlen(*pp_password)+1);
			if (!NT_STATUS_IS_OK(status)) {
                                errno = map_errno_from_nt_status(status);
                                cli_shutdown(srv->cli);
				srv->cli = NULL;
                                smbc_getFunctionRemoveCachedServer(context)(context,
                                                                            srv);
                                srv = NULL;
                        }

                        /* Determine if this share supports case sensitivity */
                        if (is_ipc) {
                                DEBUG(4,
                                      ("IPC$ so ignore case sensitivity\n"));
                        } else if (!cli_get_fs_attr_info(c, &fs_attrs)) {
                                DEBUG(4, ("Could not retrieve "
                                          "case sensitivity flag: %s.\n",
                                          cli_errstr(c)));

                                /*
                                 * We can't determine the case sensitivity of
                                 * the share. We have no choice but to use the
                                 * user-specified case sensitivity setting.
                                 */
                                if (smbc_getOptionCaseSensitive(context)) {
                                        cli_set_case_sensitive(c, True);
                                } else {
                                        cli_set_case_sensitive(c, False);
                                }
                        } else {
                                DEBUG(4,
                                      ("Case sensitive: %s\n",
                                       (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                                        ? "True"
                                        : "False")));
                                cli_set_case_sensitive(
                                        c,
                                        (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                                         ? True
                                         : False));
                        }

                        /*
                         * Regenerate the dev value since it's based on both
                         * server and share
                         */
                        if (srv) {
                                srv->dev = (dev_t)(str_checksum(srv->cli->desthost) ^
                                                   str_checksum(srv->cli->share));
                        }
                }
        }
	
        /* If we have a connection... */
        if (srv) {
                /* ... then we're done here.  Give 'em what they came for. */
		*in_cache = true;
                goto done;
        }

        /* If we're not asked to connect when a connection doesn't exist... */
        if (! connect_if_not_found) {
                /* ... then we're done here. */
                return NULL;
        }

	if (!*pp_workgroup || !*pp_username || !*pp_password) {
		errno = ENOMEM;
		return NULL;
	}

	make_nmb_name(&calling, smbc_getNetbiosName(context), 0x0);
	make_nmb_name(&called , server, 0x20);

	DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server));

	DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));

again:

	zero_sockaddr(&ss);

	/* have to open a new connection */
	if ((c = cli_initialise()) == NULL) {
		errno = ENOMEM;
		return NULL;
	}

        if (smbc_getOptionUseKerberos(context)) {
		c->use_kerberos = True;
	}

        if (smbc_getOptionFallbackAfterKerberos(context)) {
		c->fallback_after_kerberos = True;
	}

        if (smbc_getOptionUseCCache(context)) {
		c->use_ccache = True;
	}

	c->timeout = smbc_getTimeout(context);

        /*
         * Force use of port 139 for first try if share is $IPC, empty, or
         * null, so browse lists can work
         */
       if (share == NULL || *share == '\0' || is_ipc) {
                port_try_first = 139;
                port_try_next = 445;
       } else {
                port_try_first = 445;
                port_try_next = 139;
       }

	c->port = port_try_first;
	
	status = cli_connect(c, server_n, &ss);
	if (!NT_STATUS_IS_OK(status)) {

                /* First connection attempt failed.  Try alternate port. */
                c->port = port_try_next;

                status = cli_connect(c, server_n, &ss);
		if (!NT_STATUS_IS_OK(status)) {
			cli_shutdown(c);
			errno = ETIMEDOUT;
			return NULL;
		}
	}
	
	if (!cli_session_request(c, &calling, &called)) {
		cli_shutdown(c);
		if (strcmp(called.name, "*SMBSERVER")) {
			make_nmb_name(&called , "*SMBSERVER", 0x20);
			goto again;
		} else {  /* Try one more time, but ensure we don't loop */

			/* Only try this if server is an IP address ... */

			if (is_ipaddress(server) && !tried_reverse) {
				fstring remote_name;
				struct sockaddr_storage rem_ss;

				if (!interpret_string_addr(&rem_ss, server,
                                                           NI_NUMERICHOST)) {
					DEBUG(4, ("Could not convert IP address "
                                                  "%s to struct sockaddr_storage\n",
                                                  server));
					errno = ETIMEDOUT;
					return NULL;
				}

				tried_reverse++; /* Yuck */

				if (name_status_find("*", 0, 0,
                                                     &rem_ss, remote_name)) {
					make_nmb_name(&called,
                                                      remote_name,
                                                      0x20);
					goto again;
				}
			}
		}
		errno = ETIMEDOUT;
		return NULL;
	}

	DEBUG(4,(" session request ok\n"));
	

	status = cli_negprot(c);

	if (!NT_STATUS_IS_OK(status)) {
		cli_shutdown(c);
		errno = ETIMEDOUT;
		return NULL;
	}

        username_used = *pp_username;

	if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
					       *pp_password,
                                               strlen(*pp_password),
					       *pp_password,
                                               strlen(*pp_password),
					       *pp_workgroup))) {
fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_session_setup fail with username=[%s], password=[%s]\n", username_used, *pp_password);
                /* Failed.  Try an anonymous login, if allowed by flags. */
                username_used = "";

                if (smbc_getOptionNoAutoAnonymousLogin(context) ||
                    !NT_STATUS_IS_OK(cli_session_setup(c, username_used,
                                                       *pp_password, 1,
                                                       *pp_password, 0,
                                                       *pp_workgroup))) {

                        cli_shutdown(c);
                        errno = EPERM;
                        return NULL;
                }
	}
	
	status = cli_init_creds(c, username_used,
				*pp_workgroup, *pp_password);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		cli_shutdown(c);
		return NULL;
	}

	DEBUG(4,(" session setup ok\n"));
	
	/* here's the fun part....to support 'msdfs proxy' shares
	   (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
	   here before trying to connect to the original share.
	   cli_check_msdfs_proxy() will fail if it is a normal share. */

	if ((c->capabilities & CAP_DFS) &&
			cli_check_msdfs_proxy(ctx, c, share,
				&newserver, &newshare,
				/* FIXME: cli_check_msdfs_proxy() does
				   not support smbc_smb_encrypt_level type */
				context->internal->smb_encryption_level ?
					true : false,
				*pp_username,
				*pp_password,
				*pp_workgroup)) {
		cli_shutdown(c);
		srv = SMBC_server_internal(ctx, context, connect_if_not_found,
				newserver, newshare, pp_workgroup,
				pp_username, pp_password, in_cache);
		TALLOC_FREE(newserver);
		TALLOC_FREE(newshare);
		return srv;
	}
	
	/* must be a normal share */
	status = cli_tcon_andx(c, share, "?????", *pp_password,
			       strlen(*pp_password)+1);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_tcon_andx return %08X, errno=[%d]\n", NT_STATUS_V(status), errno);
		cli_shutdown(c);
		return NULL;
	}
	
	DEBUG(4,(" tconx ok\n"));

        /* Determine if this share supports case sensitivity */
	if (is_ipc) {
                DEBUG(4, ("IPC$ so ignore case sensitivity\n"));
        } else if (!cli_get_fs_attr_info(c, &fs_attrs)) {
                DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n",
                          cli_errstr(c)));

                /*
                 * We can't determine the case sensitivity of the share. We
                 * have no choice but to use the user-specified case
                 * sensitivity setting.
                 */
                if (smbc_getOptionCaseSensitive(context)) {
                        cli_set_case_sensitive(c, True);
                } else {
                        cli_set_case_sensitive(c, False);
                }
	} else {
                DEBUG(4, ("Case sensitive: %s\n",
                          (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                           ? "True"
                           : "False")));
                cli_set_case_sensitive(c,
                                       (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                                        ? True
                                        : False));
        }
	

	if (context->internal->smb_encryption_level) {
		/* Attempt UNIX smb encryption. */
		if (!NT_STATUS_IS_OK(cli_force_encryption(c,
                                                          username_used,
                                                          *pp_password,
                                                          *pp_workgroup))) {

			/*
			 * context->smb_encryption_level == 1
			 * means don't fail if encryption can't be negotiated,
			 * == 2 means fail if encryption can't be negotiated.
			 */

			DEBUG(4,(" SMB encrypt failed\n"));

			if (context->internal->smb_encryption_level == 2) {
	                        cli_shutdown(c);
				errno = EPERM;
				return NULL;
			}
		}
		DEBUG(4,(" SMB encrypt ok\n"));
	}

	/*
	 * Ok, we have got a nice connection
	 * Let's allocate a server structure.
	 */

	srv = SMB_MALLOC_P(SMBCSRV);
	if (!srv) {
		cli_shutdown(c);
		errno = ENOMEM;
		return NULL;
	}

	ZERO_STRUCTP(srv);
	srv->cli = c;
	srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
        srv->no_pathinfo = False;
        srv->no_pathinfo2 = False;
        srv->no_nt_session = False;

done:
	if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) {
		workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context));
	} else {
		workgroup = *pp_workgroup;
	}
	if(!workgroup) {
		return NULL;
	}

	/* set the credentials to make DFS work */
	smbc_set_credentials_with_fallback(context,
					   workgroup,
				    	   *pp_username,
				   	   *pp_password);

	return srv;
}
Exemple #3
0
int
SMBC_fstatvfs_ctx(SMBCCTX *context,
                  SMBCFILE *file,
                  struct statvfs *st)
{
        unsigned long flags = 0;
	uint32 fs_attrs = 0;
	struct cli_state *cli = file->srv->cli;

        /* Initialize all fields (at least until we actually use them) */
        memset(st, 0, sizeof(*st));

        /*
         * The state of each flag is such that the same bits are unset as
         * would typically be unset on a local file system on a POSIX OS. Thus
         * the bit is on, for example, only for case-insensitive file systems
         * since most POSIX file systems are case sensitive and fstatvfs()
         * would typically return zero in these bits on such a local file
         * system.
         */

        /* See if the server has UNIX CIFS support */
        if (! SERVER_HAS_UNIX_CIFS(cli)) {
                uint64_t total_allocation_units;
                uint64_t caller_allocation_units;
                uint64_t actual_allocation_units;
                uint64_t sectors_per_allocation_unit;
                uint64_t bytes_per_sector;
		NTSTATUS status;

                /* Nope. If size data is available... */
		status = cli_get_fs_full_size_info(cli,
						   &total_allocation_units,
						   &caller_allocation_units,
						   &actual_allocation_units,
						   &sectors_per_allocation_unit,
						   &bytes_per_sector);
		if (NT_STATUS_IS_OK(status)) {

                        /* ... then provide it */
                        st->f_bsize =
                                (unsigned long) bytes_per_sector;
#if HAVE_FRSIZE
                        st->f_frsize =
                                (unsigned long) sectors_per_allocation_unit;
#endif
                        st->f_blocks =
                                (fsblkcnt_t) total_allocation_units;
                        st->f_bfree =
                                (fsblkcnt_t) actual_allocation_units;
                }

                flags |= SMBC_VFS_FEATURE_NO_UNIXCIFS;
        } else {
                uint32 optimal_transfer_size;
                uint32 block_size;
                uint64_t total_blocks;
                uint64_t blocks_available;
                uint64_t user_blocks_available;
                uint64_t total_file_nodes;
                uint64_t free_file_nodes;
                uint64_t fs_identifier;
		NTSTATUS status;

                /* Has UNIXCIFS. If POSIX filesystem info is available... */
		status = cli_get_posix_fs_info(cli,
					       &optimal_transfer_size,
					       &block_size,
					       &total_blocks,
					       &blocks_available,
					       &user_blocks_available,
					       &total_file_nodes,
					       &free_file_nodes,
					       &fs_identifier);
		if (NT_STATUS_IS_OK(status)) {

                        /* ... then what's provided here takes precedence. */
                        st->f_bsize =
                                (unsigned long) block_size;
                        st->f_blocks =
                                (fsblkcnt_t) total_blocks;
                        st->f_bfree =
                                (fsblkcnt_t) blocks_available;
                        st->f_bavail =
                                (fsblkcnt_t) user_blocks_available;
                        st->f_files =
                                (fsfilcnt_t) total_file_nodes;
                        st->f_ffree =
                                (fsfilcnt_t) free_file_nodes;
#if HAVE_FSID_INT
                        st->f_fsid =
                                (unsigned long) fs_identifier;
#endif
                }
        }

        /* See if the share is case sensitive */
        if (!NT_STATUS_IS_OK(cli_get_fs_attr_info(cli, &fs_attrs))) {
                /*
                 * We can't determine the case sensitivity of
                 * the share. We have no choice but to use the
                 * user-specified case sensitivity setting.
                 */
                if (! smbc_getOptionCaseSensitive(context)) {
                        flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE;
                }
        } else {
                if (! (fs_attrs & FILE_CASE_SENSITIVE_SEARCH)) {
                        flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE;
                }
        }

        /* See if DFS is supported */
	if ((cli_state_capabilities(cli) & CAP_DFS) &&  cli->dfsroot) {
                flags |= SMBC_VFS_FEATURE_DFS;
        }

#if HAVE_STATVFS_F_FLAG
        st->f_flag = flags;
#elif HAVE_STATVFS_F_FLAGS
        st->f_flags = flags;
#endif

        return 0;
}
Exemple #4
0
static int parse_quota_set(pstring set_str, pstring username_str, enum SMB_QUOTA_TYPE *qtype, int *cmd, SMB_NTQUOTA_STRUCT *pqt)
{
	char *p = set_str,*p2;
	int todo;
	BOOL stop = False;
	BOOL enable = False;
	BOOL deny = False;
	
	if (strnequal(set_str,"UQLIM:",6)) {
		p += 6;
		*qtype = SMB_USER_QUOTA_TYPE;
		*cmd = QUOTA_SETLIM;
		todo = PARSE_LIM;
		if ((p2=strstr(p,":"))==NULL) {
			return -1;
		}
		
		*p2 = '\0';
		p2++;
		
		fstrcpy(username_str,p);
		p = p2;
	} else if (strnequal(set_str,"FSQLIM:",7)) {
		p +=7;
		*qtype = SMB_USER_FS_QUOTA_TYPE;
		*cmd = QUOTA_SETLIM;
		todo = PARSE_LIM;
	} else if (strnequal(set_str,"FSQFLAGS:",9)) {
		p +=9;
		todo = PARSE_FLAGS;
		*qtype = SMB_USER_FS_QUOTA_TYPE;
		*cmd = QUOTA_SETFLAGS;
	} else {
		return -1;
	}

	switch (todo) {
		case PARSE_LIM:
#if defined(HAVE_LONGLONG)
			if (sscanf(p,"%llu/%llu",&pqt->softlim,&pqt->hardlim)!=2) {
#else
			if (sscanf(p,"%lu/%lu",&pqt->softlim,&pqt->hardlim)!=2) {
#endif
				return -1;
			}
			
			break;
		case PARSE_FLAGS:
			while (!stop) {

				if ((p2=strstr(p,"/"))==NULL) {
					stop = True;
				} else {
					*p2 = '\0';
					p2++;
				}

				if (strnequal(p,"QUOTA_ENABLED",13)) {
					enable = True;
				} else if (strnequal(p,"DENY_DISK",9)) {
					deny = True;
				} else if (strnequal(p,"LOG_SOFTLIMIT",13)) {
					pqt->qflags |= QUOTAS_LOG_THRESHOLD;
				} else if (strnequal(p,"LOG_HARDLIMIT",13)) {
					pqt->qflags |= QUOTAS_LOG_LIMIT;
				} else {
					return -1;
				}

				p=p2;
			}

			if (deny) {
				pqt->qflags |= QUOTAS_DENY_DISK;
			} else if (enable) {
				pqt->qflags |= QUOTAS_ENABLED;
			}
			
			break;	
	}

	return 0;
}

static int do_quota(struct cli_state *cli, enum SMB_QUOTA_TYPE qtype, uint16 cmd, pstring username_str, SMB_NTQUOTA_STRUCT *pqt)
{
	uint32 fs_attrs = 0;
	int quota_fnum = 0;
	SMB_NTQUOTA_LIST *qtl = NULL;
	SMB_NTQUOTA_STRUCT qt;
	ZERO_STRUCT(qt);

	if (!cli_get_fs_attr_info(cli, &fs_attrs)) {
		d_printf("Failed to get the filesystem attributes %s.\n",
			cli_errstr(cli));
		return -1;
	}

	if (!(fs_attrs & FILE_VOLUME_QUOTAS)) {
		d_printf("Quotas are not supported by the server.\n");
		return 0;	
	}

	if (!cli_get_quota_handle(cli, &quota_fnum)) {
		d_printf("Failed to open \\%s  %s.\n",
			FAKE_FILE_NAME_QUOTA,cli_errstr(cli));
		return -1;
	}

	switch(qtype) {
		case SMB_USER_QUOTA_TYPE:
			if (!StringToSid(&qt.sid, username_str)) {
				d_printf("StringToSid() failed for [%s]\n",username_str);
				return -1;
			}
			
			switch(cmd) {
				case QUOTA_GET:
					if (!cli_get_user_quota(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_user_quota %s\n",
							 cli_errstr(cli),username_str);
						return -1;
					}
					dump_ntquota(&qt,verbose,numeric,SidToString);
					break;
				case QUOTA_SETLIM:
					pqt->sid = qt.sid;
					if (!cli_set_user_quota(cli, quota_fnum, pqt)) {
						d_printf("%s cli_set_user_quota %s\n",
							 cli_errstr(cli),username_str);
						return -1;
					}
					if (!cli_get_user_quota(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_user_quota %s\n",
							 cli_errstr(cli),username_str);
						return -1;
					}
					dump_ntquota(&qt,verbose,numeric,SidToString);
					break;
				case QUOTA_LIST:
					if (!cli_list_user_quota(cli, quota_fnum, &qtl)) {
						d_printf("%s cli_set_user_quota %s\n",
							 cli_errstr(cli),username_str);
						return -1;
					}
					dump_ntquota_list(&qtl,verbose,numeric,SidToString);
					free_ntquota_list(&qtl);					
					break;
				default:
					d_printf("Unknown Error\n");
					return -1;
			} 
			break;
		case SMB_USER_FS_QUOTA_TYPE:
			switch(cmd) {
				case QUOTA_GET:
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					dump_ntquota(&qt,True,numeric,NULL);
					break;
				case QUOTA_SETLIM:
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					qt.softlim = pqt->softlim;
					qt.hardlim = pqt->hardlim;
					if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_set_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					dump_ntquota(&qt,True,numeric,NULL);
					break;
				case QUOTA_SETFLAGS:
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					qt.qflags = pqt->qflags;
					if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_set_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					dump_ntquota(&qt,True,numeric,NULL);
					break;
				default:
					d_printf("Unknown Error\n");
					return -1;
			} 		
			break;
		default:
			d_printf("Unknown Error\n");
			return -1;
	}

	cli_close(cli, quota_fnum);

	return 0;
}
Exemple #5
0
static int do_quota(struct cli_state *cli,
		enum SMB_QUOTA_TYPE qtype,
		uint16_t cmd,
		const char *username_str,
		SMB_NTQUOTA_STRUCT *pqt)
{
	uint32_t fs_attrs = 0;
	uint16_t quota_fnum = 0;
	SMB_NTQUOTA_LIST *qtl = NULL;
	TALLOC_CTX *qtl_ctx = NULL;
	SMB_NTQUOTA_STRUCT qt;
	NTSTATUS status;

	ZERO_STRUCT(qt);

	status = cli_get_fs_attr_info(cli, &fs_attrs);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Failed to get the filesystem attributes %s.\n",
			 nt_errstr(status));
		return -1;
	}

	if (!(fs_attrs & FILE_VOLUME_QUOTAS)) {
		d_printf("Quotas are not supported by the server.\n");
		return 0;
	}

	status = cli_get_quota_handle(cli, &quota_fnum);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Quotas are not enabled on this share.\n");
		d_printf("Failed to open %s  %s.\n",
			 FAKE_FILE_NAME_QUOTA_WIN32,
			 nt_errstr(status));
		return -1;
	}

	switch(qtype) {
		case SMB_USER_QUOTA_TYPE:
			if (!StringToSid(&qt.sid, username_str)) {
				d_printf("StringToSid() failed for [%s]\n",username_str);
				return -1;
			}

			switch(cmd) {
				case QUOTA_GET:
					status = cli_get_user_quota(
						cli, quota_fnum, &qt);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_get_user_quota %s\n",
							 nt_errstr(status),
							 username_str);
						return -1;
					}
					dump_ntquota(&qt,verbose,numeric,SidToString);
					break;
				case QUOTA_SETLIM:
					pqt->sid = qt.sid;
					if ((qtl_ctx = talloc_init(
						 "SMB_USER_QUOTA_SET")) ==
					    NULL) {
						return -1;
					}

					if (!add_record_to_ntquota_list(
						qtl_ctx, pqt, &qtl)) {
						TALLOC_FREE(qtl_ctx);
						return -1;
					}

					status = cli_set_user_quota(
					    cli, quota_fnum, qtl);
					free_ntquota_list(&qtl);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_set_user_quota %s\n",
							 nt_errstr(status),
							 username_str);
						return -1;
					}
					status = cli_get_user_quota(
						cli, quota_fnum, &qt);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_get_user_quota %s\n",
							 nt_errstr(status),
							 username_str);
						return -1;
					}
					dump_ntquota(&qt,verbose,numeric,SidToString);
					break;
				case QUOTA_LIST:
					status = cli_list_user_quota(
						cli, quota_fnum, &qtl);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf(
						    "%s cli_list_user_quota\n",
						    nt_errstr(status));
						return -1;
					}
					dump_ntquota_list(&qtl,verbose,numeric,SidToString);
					free_ntquota_list(&qtl);
					break;
				default:
					d_printf("Unknown Error\n");
					return -1;
			}
			break;
		case SMB_USER_FS_QUOTA_TYPE:
			switch(cmd) {
				case QUOTA_GET:
					status = cli_get_fs_quota_info(
						cli, quota_fnum, &qt);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 nt_errstr(status));
						return -1;
					}
					dump_ntquota(&qt,True,numeric,NULL);
					break;
				case QUOTA_SETLIM:
					status = cli_get_fs_quota_info(
						cli, quota_fnum, &qt);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 nt_errstr(status));
						return -1;
					}
					qt.softlim = pqt->softlim;
					qt.hardlim = pqt->hardlim;
					status = cli_set_fs_quota_info(
						cli, quota_fnum, &qt);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_set_fs_quota_info\n",
							 nt_errstr(status));
						return -1;
					}
					status = cli_get_fs_quota_info(
						cli, quota_fnum, &qt);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 nt_errstr(status));
						return -1;
					}
					dump_ntquota(&qt,True,numeric,NULL);
					break;
				case QUOTA_SETFLAGS:
					status = cli_get_fs_quota_info(
						cli, quota_fnum, &qt);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 nt_errstr(status));
						return -1;
					}
					qt.qflags = pqt->qflags;
					status = cli_set_fs_quota_info(
						cli, quota_fnum, &qt);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_set_fs_quota_info\n",
							 nt_errstr(status));
						return -1;
					}
					status = cli_get_fs_quota_info(
						cli, quota_fnum, &qt);
					if (!NT_STATUS_IS_OK(status)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 nt_errstr(status));
						return -1;
					}
					dump_ntquota(&qt,True,numeric,NULL);
					break;
				default:
					d_printf("Unknown Error\n");
					return -1;
			}
			break;
		default:
			d_printf("Unknown Error\n");
			return -1;
	}

	cli_close(cli, quota_fnum);

	return 0;
}
Exemple #6
0
static int do_quota(struct cli_state *cli,
		enum SMB_QUOTA_TYPE qtype,
		uint16 cmd,
		const char *username_str,
		SMB_NTQUOTA_STRUCT *pqt)
{
	uint32 fs_attrs = 0;
	int quota_fnum = 0;
	SMB_NTQUOTA_LIST *qtl = NULL;
	SMB_NTQUOTA_STRUCT qt;
	ZERO_STRUCT(qt);

	if (!cli_get_fs_attr_info(cli, &fs_attrs)) {
		d_printf("Failed to get the filesystem attributes %s.\n",
			cli_errstr(cli));
		return -1;
	}

	if (!(fs_attrs & FILE_VOLUME_QUOTAS)) {
		d_printf("Quotas are not supported by the server.\n");
		return 0;
	}

	if (!cli_get_quota_handle(cli, &quota_fnum)) {
		d_printf("Quotas are not enabled on this share.\n");
		d_printf("Failed to open %s  %s.\n",
			FAKE_FILE_NAME_QUOTA_WIN32,cli_errstr(cli));
		return -1;
	}

	switch(qtype) {
		case SMB_USER_QUOTA_TYPE:
			if (!StringToSid(&qt.sid, username_str)) {
				d_printf("StringToSid() failed for [%s]\n",username_str);
				return -1;
			}

			switch(cmd) {
				case QUOTA_GET:
					if (!cli_get_user_quota(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_user_quota %s\n",
							 cli_errstr(cli),username_str);
						return -1;
					}
					dump_ntquota(&qt,verbose,numeric,SidToString);
					break;
				case QUOTA_SETLIM:
					pqt->sid = qt.sid;
					if (!cli_set_user_quota(cli, quota_fnum, pqt)) {
						d_printf("%s cli_set_user_quota %s\n",
							 cli_errstr(cli),username_str);
						return -1;
					}
					if (!cli_get_user_quota(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_user_quota %s\n",
							 cli_errstr(cli),username_str);
						return -1;
					}
					dump_ntquota(&qt,verbose,numeric,SidToString);
					break;
				case QUOTA_LIST:
					if (!cli_list_user_quota(cli, quota_fnum, &qtl)) {
						d_printf("%s cli_set_user_quota %s\n",
							 cli_errstr(cli),username_str);
						return -1;
					}
					dump_ntquota_list(&qtl,verbose,numeric,SidToString);
					free_ntquota_list(&qtl);
					break;
				default:
					d_printf("Unknown Error\n");
					return -1;
			}
			break;
		case SMB_USER_FS_QUOTA_TYPE:
			switch(cmd) {
				case QUOTA_GET:
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					dump_ntquota(&qt,True,numeric,NULL);
					break;
				case QUOTA_SETLIM:
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					qt.softlim = pqt->softlim;
					qt.hardlim = pqt->hardlim;
					if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_set_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					dump_ntquota(&qt,True,numeric,NULL);
					break;
				case QUOTA_SETFLAGS:
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					qt.qflags = pqt->qflags;
					if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_set_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) {
						d_printf("%s cli_get_fs_quota_info\n",
							 cli_errstr(cli));
						return -1;
					}
					dump_ntquota(&qt,True,numeric,NULL);
					break;
				default:
					d_printf("Unknown Error\n");
					return -1;
			}
			break;
		default:
			d_printf("Unknown Error\n");
			return -1;
	}

	cli_close(cli, quota_fnum);

	return 0;
}