/* * 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; }