Beispiel #1
0
/*
 * NNTP user authorization. Returns TRUE if authorization succeeded,
 * FALSE if not.
 *
 * tries AUTHINFO SASL PLAIN (if available) fist and if not succcessfull
 * AUTHINFO USER/PASS
 *
 * If username/passwd already given, and server wasn't changed, retry those.
 * Otherwise, read password from ~/.newsauth or, if not present or no matching
 * server found, from console.
 *
 * The ~/.newsauth authorization file has the format:
 *   nntpserver1 password [user]
 *   nntpserver2 password [user]
 *   etc.
 */
static t_bool
authinfo_plain(
	char *server,
	char *authuser,
	t_bool startup)
{
	char *authpass;
	int ret = ERR_AUTHBAD, changed;
	static char authusername[PATH_LEN] = "";
	static char authpassword[PATH_LEN] = "";
	static char last_server[PATH_LEN] = "";
	static t_bool already_failed = FALSE;
	static t_bool initialized = FALSE;

	changed = strcmp(server, last_server);	/* do we need new auth values? */
	strncpy(last_server, server, PATH_LEN - 1);
	last_server[PATH_LEN - 1] = '\0';

	/*
	 * Let's try the previous auth pair first, if applicable.
	 * Else, proceed to the other mechanisms.
	 */
	if (initialized && !changed && !already_failed) {
#	ifdef USE_SASL
		if (nntp_caps.sasl & SASL_PLAIN)
			ret = do_authinfo_sasl_plain(authusername, authpassword);
		if (ret != OK_AUTH)
#	endif /* USE_SASL */
		{
			if (nntp_caps.type != CAPABILITIES || nntp_caps.authinfo_user)
				ret = do_authinfo_user(server, authusername, authpassword);
		}
		return (ret == OK_AUTH);
	}

	authpassword[0] = '\0';
	authuser = strncpy(authusername, authuser, sizeof(authusername) - 1);
	authpass = authpassword;

	/*
	 * No username/password given yet.
	 * Read .newsauth only if we had not failed authentication yet for the
	 * current server (we don't want to try wrong username/password pairs
	 * more than once because this may lead to an infinite loop at connection
	 * startup: nntp_open tries to authenticate, it fails, server closes
	 * connection; next time tin tries to access the server it will do
	 * nntp_open again ...). This means, however, that if configuration
	 * changed on the server between two authentication attempts tin will
	 * prompt you the second time instead of reading .newsauth (except when
	 * at startup time; in this case, it will just leave); you have to leave
	 * and restart tin or change to another server and back in order to get
	 * it read again.
	 */
	if ((changed || !initialized) && !already_failed) {
		if (read_newsauth_file(server, authuser, authpass)) {
#	ifdef USE_SASL
			if (nntp_caps.sasl & SASL_PLAIN)
				ret = do_authinfo_sasl_plain(authuser, authpass);

			if (ret != OK_AUTH)
#	endif /* USE_SASL */
			{
				if (force_auth_on_conn_open || nntp_caps.type != CAPABILITIES || (nntp_caps.type == CAPABILITIES && nntp_caps.authinfo_user))
					ret = do_authinfo_user(server, authuser, authpass);
			}
			already_failed = (ret != OK_AUTH);

			if (ret == OK_AUTH) {
#	ifdef DEBUG
				if (debug & DEBUG_NNTP)
					debug_print_file("NNTP", "authorization succeeded");
#	endif /* DEBUG */
				initialized = TRUE;
				return TRUE;
			}
		}
	}

	/*
	 * At this point, either authentication with username/password pair from
	 * .newsauth has failed or there's no .newsauth file respectively no
	 * matching username/password for the current server. If we are not at
	 * startup we ask the user to enter such a pair by hand. Don't ask him
	 * at startup except if requested by -A option because if he doesn't need
	 * to authenticate (we don't know), the "Server expects authentication"
	 * messages are annoying (and even wrong).
	 * UNSURE: Maybe we want to make this decision configurable in the
	 * options menu, too, so that the user doesn't need -A.
	 * TODO: Put questions into do_authinfo_user() because it is possible
	 * that the server doesn't want a password; so only ask for it if needed.
	 */
	if (force_auth_on_conn_open || !startup) {
		if (batch_mode) { /* no interactive username/password prompting */
			error_message(0, _(txt_auth_needed));
			return (ret == OK_AUTH);
		}
		if (nntp_caps.type != CAPABILITIES || (nntp_caps.type == CAPABILITIES && !nntp_caps.authinfo_state && ((nntp_caps.sasl & SASL_PLAIN) || nntp_caps.authinfo_user || (!nntp_caps.authinfo_user && !(nntp_caps.sasl & SASL_PLAIN))))) {
#	ifdef USE_CURSES
			int state = RawState();
#	endif /* USE_CURSES */

			wait_message(0, _(txt_auth_needed));
#	ifdef USE_CURSES
			Raw(TRUE);
#	endif /* USE_CURSES */
			if (!prompt_default_string(_(txt_auth_user), authuser, PATH_LEN, authusername, HIST_NONE)) {
#	ifdef DEBUG
				if (debug & DEBUG_NNTP)
					debug_print_file("NNTP", "authorization failed: no username");
#	endif /* DEBUG */
				return FALSE;
			}

#	ifdef USE_CURSES
			Raw(state);
			my_printf("%s", _(txt_auth_pass));
			wgetnstr(stdscr, authpassword, sizeof(authpassword));
			Raw(TRUE);
#	else
			/*
			 * on some systems (i.e. Solaris) getpass(3) is limited to 8 chars ->
			 * we use tin_getline()
			 */
			authpass = strncpy(authpassword, tin_getline(_(txt_auth_pass), FALSE, NULL, PATH_LEN, TRUE, HIST_NONE), sizeof(authpassword) - 1);
#	endif /* USE_CURSES */

#	ifdef USE_SASL
			if (nntp_caps.sasl & SASL_PLAIN)
				ret = do_authinfo_sasl_plain(authuser, authpass);
			if (ret != OK_AUTH)
#	endif /* USE_SASL */
			{
				if (nntp_caps.type != CAPABILITIES || (nntp_caps.authinfo_user || !nntp_caps.authinfo_sasl)) {
#	ifdef DEBUG
					if (debug & DEBUG_NNTP) {
						if (nntp_caps.type == CAPABILITIES && !nntp_caps.authinfo_sasl && !nntp_caps.authinfo_user)
							debug_print_file("NNTP", "!!! No supported authmethod available, trying AUTHINFO USER/PASS");
					}
#	endif /* DEBUG */
					ret = do_authinfo_user(server, authuser, authpass);
					if (ret != OK_AUTH)
						already_failed = TRUE;
					/*
					 * giganews once responded to CAPABILITIES with just
					 * "VERSION 2", no mode-switching indication, no reader
					 * indication, no post indication, no authentication
					 * indication, ... so in case AUTHINFO USER/PASS succeeds
					 * if not advertized we simply go on but fully ignore
					 * CAPABILITIES
					 */
					if (nntp_caps.type == CAPABILITIES && !nntp_caps.authinfo_user && !nntp_caps.authinfo_sasl && ret == OK_AUTH)
						nntp_caps.type = BROKEN;
				}
			}
			initialized = TRUE;
			my_retouch();			/* Get rid of the chaff */
		} else {
			/*
			 * TODO:
			 * nntp_caps.type == CAPABILITIES && nntp_caps.authinfo_state
			 * can we change the sate here? and if so how? SARTTLS? MODE
			 * READER?
			 */
#	ifdef DEBUG
			if (debug & DEBUG_NNTP)
				debug_print_file("NNTP", "authorization not allowed in current sate");
#	endif /* DEBUG */
			/*
			 * we return OK_AUTH here once so tin doesn't exit just because a
			 * single command requested auth ...
			 */
			if (!already_failed)
				ret = OK_AUTH;
		}
	}

#	ifdef DEBUG
	if (debug & DEBUG_NNTP)
		debug_print_file("NNTP", "authorization %s", (ret == OK_AUTH ? "succeeded" : "failed"));
#	endif /* DEBUG */

	return (ret == OK_AUTH);
}
int
subshell()
{
	/** spawn a subshell with either the specified command
	    returns non-zero if screen rewrite needed
	**/

	char command[SLEN];
	int  old_raw, helpful, ret;

	helpful = (user_level == 0);

	if (helpful)
	  PutLine0(LINES-3, COLUMNS-40, catgets(elm_msg_cat, ElmSet, ElmUseShellName,
		"(Use the shell name for a shell.)"));
	PutLine0(LINES-2, 0, catgets(elm_msg_cat, ElmSet, ElmShellCommand,
		"Shell command: "));
	CleartoEOS();
	command[0] = '\0';
	(void) optionally_enter(command, LINES-2, 15, FALSE, FALSE);
	if (command[0] == 0) {
	  if (helpful)
	    MoveCursor(LINES-3,COLUMNS-40);
	  else
	    MoveCursor(LINES-2,0);
	  CleartoEOS();
	  return 0;
	}

	MoveCursor(LINES,0);
	CleartoEOLN();

	if ((old_raw = RawState()) == ON)
	  Raw(OFF);
	softkeys_off();
	if (cursor_control)
	  transmit_functions(OFF);

	umask(original_umask);	/* restore original umask so users new files are ok */
	ret = system_call(command, SY_USER_SHELL|SY_ENAB_SIGINT|SY_DUMPSTATE);
	umask(077);		/* now put it back to private for mail files */

	SetXYLocation(0, 40);	/* a location not near the next request, so an absolute is used */
	PutLine0(LINES, 0, catgets(elm_msg_cat, ElmSet, ElmPressAnyKeyToReturn,
		"\n\nPress any key to return to ELM: "));
	Raw(ON | NO_TITE);
	(void) getchar();
	printf("\r\n");
	Raw(OFF | NO_TITE); /* Done even if old_raw == ON, to get ti/te right */
	if (old_raw == ON)
	  Raw(ON);

	softkeys_on();
	if (cursor_control)
	  transmit_functions(ON);

	if (ret)
	  error1(catgets(elm_msg_cat, ElmSet, ElmReturnCodeWas,
		"Return code was %d."), ret);

	return 1;
}