From b5965290417200a52da1f4c87f745a7044e84453 Mon Sep 17 00:00:00 2001 From: Kai Blin Date: Tue, 13 May 2008 21:18:09 +0200 Subject: net: Move more utility functions into net_util.c (This used to be commit 0f5ebdf0bc5610bf93a4db67c9f9513683306c66) --- source3/utils/net_util.c | 466 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) (limited to 'source3/utils/net_util.c') diff --git a/source3/utils/net_util.c b/source3/utils/net_util.c index ebf9fe9993..771c7e4f46 100644 --- a/source3/utils/net_util.c +++ b/source3/utils/net_util.c @@ -80,3 +80,469 @@ NTSTATUS net_rpc_lookup_name(struct net_context *c, return result; } + +/**************************************************************************** + Connect to \\server\service. +****************************************************************************/ + +NTSTATUS connect_to_service(struct net_context *c, + struct cli_state **cli_ctx, + struct sockaddr_storage *server_ss, + const char *server_name, + const char *service_name, + const char *service_type) +{ + NTSTATUS nt_status; + + c->opt_password = net_prompt_pass(c, c->opt_user_name); + if (!c->opt_password) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = cli_full_connection(cli_ctx, NULL, server_name, + server_ss, c->opt_port, + service_name, service_type, + c->opt_user_name, c->opt_workgroup, + c->opt_password, 0, Undefined, NULL); + if (!NT_STATUS_IS_OK(nt_status)) { + d_fprintf(stderr, "Could not connect to server %s\n", server_name); + + /* Display a nicer message depending on the result */ + + if (NT_STATUS_V(nt_status) == + NT_STATUS_V(NT_STATUS_LOGON_FAILURE)) + d_fprintf(stderr, "The username or password was not correct.\n"); + + if (NT_STATUS_V(nt_status) == + NT_STATUS_V(NT_STATUS_ACCOUNT_LOCKED_OUT)) + d_fprintf(stderr, "The account was locked out.\n"); + + if (NT_STATUS_V(nt_status) == + NT_STATUS_V(NT_STATUS_ACCOUNT_DISABLED)) + d_fprintf(stderr, "The account was disabled.\n"); + return nt_status; + } + + if (c->smb_encrypt) { + nt_status = cli_force_encryption(*cli_ctx, + c->opt_user_name, + c->opt_password, + c->opt_workgroup); + + if (NT_STATUS_EQUAL(nt_status,NT_STATUS_NOT_SUPPORTED)) { + d_printf("Encryption required and " + "server that doesn't support " + "UNIX extensions - failing connect\n"); + } else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNKNOWN_REVISION)) { + d_printf("Encryption required and " + "can't get UNIX CIFS extensions " + "version from server.\n"); + } else if (NT_STATUS_EQUAL(nt_status,NT_STATUS_UNSUPPORTED_COMPRESSION)) { + d_printf("Encryption required and " + "share %s doesn't support " + "encryption.\n", service_name); + } else if (!NT_STATUS_IS_OK(nt_status)) { + d_printf("Encryption required and " + "setup failed with error %s.\n", + nt_errstr(nt_status)); + } + + if (!NT_STATUS_IS_OK(nt_status)) { + cli_shutdown(*cli_ctx); + *cli_ctx = NULL; + } + } + + return nt_status; +} + +/**************************************************************************** + Connect to \\server\ipc$. +****************************************************************************/ + +NTSTATUS connect_to_ipc(struct net_context *c, + struct cli_state **cli_ctx, + struct sockaddr_storage *server_ss, + const char *server_name) +{ + return connect_to_service(c, cli_ctx, server_ss, server_name, "IPC$", + "IPC"); +} + +/**************************************************************************** + Connect to \\server\ipc$ anonymously. +****************************************************************************/ + +NTSTATUS connect_to_ipc_anonymous(struct net_context *c, + struct cli_state **cli_ctx, + struct sockaddr_storage *server_ss, + const char *server_name) +{ + NTSTATUS nt_status; + + nt_status = cli_full_connection(cli_ctx, c->opt_requester_name, + server_name, server_ss, c->opt_port, + "IPC$", "IPC", + "", "", + "", 0, Undefined, NULL); + + if (NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } else { + DEBUG(1,("Cannot connect to server (anonymously). Error was %s\n", nt_errstr(nt_status))); + return nt_status; + } +} + +/**************************************************************************** + Return malloced user@realm for krb5 login. +****************************************************************************/ + +static char *get_user_and_realm(const char *username) +{ + char *user_and_realm = NULL; + + if (!username) { + return NULL; + } + if (strchr_m(username, '@')) { + user_and_realm = SMB_STRDUP(username); + } else { + if (asprintf(&user_and_realm, "%s@%s", username, lp_realm()) == -1) { + user_and_realm = NULL; + } + } + return user_and_realm; +} + +/**************************************************************************** + Connect to \\server\ipc$ using KRB5. +****************************************************************************/ + +NTSTATUS connect_to_ipc_krb5(struct net_context *c, + struct cli_state **cli_ctx, + struct sockaddr_storage *server_ss, + const char *server_name) +{ + NTSTATUS nt_status; + char *user_and_realm = NULL; + + /* FIXME: Should get existing kerberos ticket if possible. */ + c->opt_password = net_prompt_pass(c, c->opt_user_name); + if (!c->opt_password) { + return NT_STATUS_NO_MEMORY; + } + + user_and_realm = get_user_and_realm(c->opt_user_name); + if (!user_and_realm) { + return NT_STATUS_NO_MEMORY; + } + + nt_status = cli_full_connection(cli_ctx, NULL, server_name, + server_ss, c->opt_port, + "IPC$", "IPC", + user_and_realm, c->opt_workgroup, + c->opt_password, + CLI_FULL_CONNECTION_USE_KERBEROS, + Undefined, NULL); + + SAFE_FREE(user_and_realm); + + if (!NT_STATUS_IS_OK(nt_status)) { + DEBUG(1,("Cannot connect to server using kerberos. Error was %s\n", nt_errstr(nt_status))); + return nt_status; + } + + if (c->smb_encrypt) { + nt_status = cli_cm_force_encryption(*cli_ctx, + user_and_realm, + c->opt_password, + c->opt_workgroup, + "IPC$"); + if (!NT_STATUS_IS_OK(nt_status)) { + cli_shutdown(*cli_ctx); + *cli_ctx = NULL; + } + } + + return nt_status; +} + +/** + * Connect a server and open a given pipe + * + * @param cli_dst A cli_state + * @param pipe The pipe to open + * @param got_pipe boolean that stores if we got a pipe + * + * @return Normal NTSTATUS return. + **/ +NTSTATUS connect_dst_pipe(struct net_context *c, struct cli_state **cli_dst, + struct rpc_pipe_client **pp_pipe_hnd, int pipe_num) +{ + NTSTATUS nt_status; + char *server_name = SMB_STRDUP("127.0.0.1"); + struct cli_state *cli_tmp = NULL; + struct rpc_pipe_client *pipe_hnd = NULL; + + if (server_name == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (c->opt_destination) { + SAFE_FREE(server_name); + if ((server_name = SMB_STRDUP(c->opt_destination)) == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + + /* make a connection to a named pipe */ + nt_status = connect_to_ipc(c, &cli_tmp, NULL, server_name); + if (!NT_STATUS_IS_OK(nt_status)) { + SAFE_FREE(server_name); + return nt_status; + } + + pipe_hnd = cli_rpc_pipe_open_noauth(cli_tmp, pipe_num, &nt_status); + if (!pipe_hnd) { + DEBUG(0, ("couldn't not initialize pipe\n")); + cli_shutdown(cli_tmp); + SAFE_FREE(server_name); + return nt_status; + } + + *cli_dst = cli_tmp; + *pp_pipe_hnd = pipe_hnd; + SAFE_FREE(server_name); + + return nt_status; +} + +/**************************************************************************** + Use the local machine account (krb) and password for this session. +****************************************************************************/ + +int net_use_krb_machine_account(struct net_context *c) +{ + char *user_name = NULL; + + if (!secrets_init()) { + d_fprintf(stderr, "ERROR: Unable to open secrets database\n"); + exit(1); + } + + c->opt_password = secrets_fetch_machine_password( + c->opt_target_workgroup, NULL, NULL); + if (asprintf(&user_name, "%s$@%s", global_myname(), lp_realm()) == -1) { + return -1; + } + c->opt_user_name = user_name; + return 0; +} + +/**************************************************************************** + Use the machine account name and password for this session. +****************************************************************************/ + +int net_use_machine_account(struct net_context *c) +{ + char *user_name = NULL; + + if (!secrets_init()) { + d_fprintf(stderr, "ERROR: Unable to open secrets database\n"); + exit(1); + } + + c->opt_password = secrets_fetch_machine_password( + c->opt_target_workgroup, NULL, NULL); + if (asprintf(&user_name, "%s$", global_myname()) == -1) { + return -1; + } + c->opt_user_name = user_name; + return 0; +} + +bool net_find_server(struct net_context *c, + const char *domain, + unsigned flags, + struct sockaddr_storage *server_ss, + char **server_name) +{ + const char *d = domain ? domain : c->opt_target_workgroup; + + if (c->opt_host) { + *server_name = SMB_STRDUP(c->opt_host); + } + + if (c->opt_have_ip) { + *server_ss = c->opt_dest_ip; + if (!*server_name) { + char addr[INET6_ADDRSTRLEN]; + print_sockaddr(addr, sizeof(addr), &c->opt_dest_ip); + *server_name = SMB_STRDUP(addr); + } + } else if (*server_name) { + /* resolve the IP address */ + if (!resolve_name(*server_name, server_ss, 0x20)) { + DEBUG(1,("Unable to resolve server name\n")); + return false; + } + } else if (flags & NET_FLAGS_PDC) { + fstring dc_name; + struct sockaddr_storage pdc_ss; + + if (!get_pdc_ip(d, &pdc_ss)) { + DEBUG(1,("Unable to resolve PDC server address\n")); + return false; + } + + if (is_zero_addr(&pdc_ss)) { + return false; + } + + if (!name_status_find(d, 0x1b, 0x20, &pdc_ss, dc_name)) { + return false; + } + + *server_name = SMB_STRDUP(dc_name); + *server_ss = pdc_ss; + } else if (flags & NET_FLAGS_DMB) { + struct sockaddr_storage msbrow_ss; + char addr[INET6_ADDRSTRLEN]; + + /* if (!resolve_name(MSBROWSE, &msbrow_ip, 1)) */ + if (!resolve_name(d, &msbrow_ss, 0x1B)) { + DEBUG(1,("Unable to resolve domain browser via name lookup\n")); + return false; + } + *server_ss = msbrow_ss; + print_sockaddr(addr, sizeof(addr), server_ss); + *server_name = SMB_STRDUP(addr); + } else if (flags & NET_FLAGS_MASTER) { + struct sockaddr_storage brow_ss; + char addr[INET6_ADDRSTRLEN]; + if (!resolve_name(d, &brow_ss, 0x1D)) { + /* go looking for workgroups */ + DEBUG(1,("Unable to resolve master browser via name lookup\n")); + return false; + } + *server_ss = brow_ss; + print_sockaddr(addr, sizeof(addr), server_ss); + *server_name = SMB_STRDUP(addr); + } else if (!(flags & NET_FLAGS_LOCALHOST_DEFAULT_INSANE)) { + if (!interpret_string_addr(server_ss, + "127.0.0.1", AI_NUMERICHOST)) { + DEBUG(1,("Unable to resolve 127.0.0.1\n")); + return false; + } + *server_name = SMB_STRDUP("127.0.0.1"); + } + + if (!*server_name) { + DEBUG(1,("no server to connect to\n")); + return false; + } + + return true; +} + +bool net_find_pdc(struct sockaddr_storage *server_ss, + fstring server_name, + const char *domain_name) +{ + if (!get_pdc_ip(domain_name, server_ss)) { + return false; + } + if (is_zero_addr(server_ss)) { + return false; + } + + if (!name_status_find(domain_name, 0x1b, 0x20, server_ss, server_name)) { + return false; + } + + return true; +} + +NTSTATUS net_make_ipc_connection(struct net_context *c, unsigned flags, + struct cli_state **pcli) +{ + return net_make_ipc_connection_ex(c, NULL, NULL, NULL, flags, pcli); +} + +NTSTATUS net_make_ipc_connection_ex(struct net_context *c ,const char *domain, + const char *server, + struct sockaddr_storage *pss, + unsigned flags, struct cli_state **pcli) +{ + char *server_name = NULL; + struct sockaddr_storage server_ss; + struct cli_state *cli = NULL; + NTSTATUS nt_status; + + if ( !server || !pss ) { + if (!net_find_server(c, domain, flags, &server_ss, + &server_name)) { + d_fprintf(stderr, "Unable to find a suitable server\n"); + nt_status = NT_STATUS_UNSUCCESSFUL; + goto done; + } + } else { + server_name = SMB_STRDUP( server ); + server_ss = *pss; + } + + if (flags & NET_FLAGS_ANONYMOUS) { + nt_status = connect_to_ipc_anonymous(c, &cli, &server_ss, + server_name); + } else { + nt_status = connect_to_ipc(c, &cli, &server_ss, + server_name); + } + + /* store the server in the affinity cache if it was a PDC */ + + if ( (flags & NET_FLAGS_PDC) && NT_STATUS_IS_OK(nt_status) ) + saf_store( cli->server_domain, cli->desthost ); + + SAFE_FREE(server_name); + if (!NT_STATUS_IS_OK(nt_status)) { + d_fprintf(stderr, "Connection failed: %s\n", + nt_errstr(nt_status)); + cli = NULL; + } + +done: + if (pcli != NULL) { + *pcli = cli; + } + return nt_status; +} + +/**************************************************************************** +****************************************************************************/ + +const char *net_prompt_pass(struct net_context *c, const char *user) +{ + char *prompt = NULL; + const char *pass = NULL; + + if (c->opt_password) { + return c->opt_password; + } + + if (c->opt_machine_pass) { + return NULL; + } + + asprintf(&prompt, "Enter %s's password:", user); + if (!prompt) { + return NULL; + } + + pass = getpass(prompt); + SAFE_FREE(prompt); + + return pass; +} + -- cgit