Je veux masquer mon mot de passe en l'écrivant avec *
. J'utilise Linux GCC pour ce code. Je sais qu'une solution consiste à utiliser la fonction getch()
comme celle-ci
#include <conio.h>
int main()
{
char c,password[10];
int i;
while( (c=getch())!= '\n');{
password[i] = c;
printf("*");
i++;
}
return 1;
}
mais le problème est que GCC
n'inclut pas le fichier conio.h
donc, getch()
est inutile pour moi. Quelqu'un a-t-il une solution?
Dans le monde Linux, le masquage ne se fait généralement pas avec des astérisques, normalement l'écho est simplement désactivé et le terminal affiche des blancs Par exemple. si vous utilisez su
ou vous connectez à un terminal virtuel, etc.
Il existe une fonction de bibliothèque pour gérer l'obtention des mots de passe, elle ne masquera pas le mot de passe avec des astérisques mais désactivera l'écho du mot de passe sur le terminal. Je l'ai retiré d'un livre Linux que j'ai. Je crois que cela fait partie de la norme posix
#include <unistd.h> char *getpass(const char *Prompt); /*Returns pointer to statically allocated input password string on success, or NULL on error*/
La fonction getpass () désactive d'abord l'écho et tout traitement des caractères spéciaux du terminal (tels que le caractère d'interruption, normalement Control-C).
Il imprime ensuite la chaîne pointée par Prompt et lit une ligne d'entrée, renvoyant la chaîne d'entrée terminée par le null avec la nouvelle ligne de fin supprimée, comme résultat de sa fonction.
Une recherche Google pour getpass () a une référence à l'implémentation GNU (devrait être dans la plupart des distributions Linux) et un exemple de code pour implémenter la vôtre si besoin est
http://www.gnu.org/s/hello/manual/libc/getpass.html
Leur exemple pour rouler le vôtre:
#include <termios.h>
#include <stdio.h>
ssize_t
my_getpass (char **lineptr, size_t *n, FILE *stream)
{
struct termios old, new;
int nread;
/* Turn echoing off and fail if we can't. */
if (tcgetattr (fileno (stream), &old) != 0)
return -1;
new = old;
new.c_lflag &= ~ECHO;
if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0)
return -1;
/* Read the password. */
nread = getline (lineptr, n, stream);
/* Restore terminal. */
(void) tcsetattr (fileno (stream), TCSAFLUSH, &old);
return nread;
}
Si nécessaire, vous pouvez l'utiliser comme base pour le modifier afin d'afficher des astérisques.
Sans getch
sur lequel s'appuyer et en évitant le getpass
obsolète, l'approche recommandée consiste à désactiver le terminal ECHO via termios
. Après quelques recherches pour trouver une routine de mot de passe flexible en conserve, j'ai été surpris que très peu pour une utilisation autonome avec C. Plutôt que de simplement recoder getch
avec termios c_lflag
options, l'approche légèrement plus généralisée ne nécessite que quelques ajouts. Au-delà du remplacement de getch
, toute routine doit appliquer une longueur maximale spécifiée pour éviter le débordement, tronquer si l'utilisateur tente d'entrer au-delà du maximum et avertir si la troncature se produit d'une manière ou d'une autre.
Ci-dessous, les ajouts permettront la lecture de tout FILE *
le flux d'entrée, limitant la longueur à une longueur spécifiée, offre une capacité d'édition minimale (retour arrière) lors de la prise de saisie, permet de spécifier ou de désactiver complètement le masque de caractères, et finalement de renvoyer la longueur du mot de passe entré. Un avertissement a été ajouté lorsque le mot de passe saisi a été tronqué à la longueur maximale ou spécifiée.
Espérons que cela se révélera utile aux autres avec cette question à la recherche d'une solution similaire:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <termios.h>
#include <errno.h> /* for errno */
#include <unistd.h> /* for EINTR */
#define MAXPW 32
/* read a string from fp into pw masking keypress with mask char.
getpasswd will read upto sz - 1 chars into pw, null-terminating
the resulting string. On success, the number of characters in
pw are returned, -1 otherwise.
*/
ssize_t getpasswd (char **pw, size_t sz, int mask, FILE *fp)
{
if (!pw || !sz || !fp) return -1; /* validate input */
#ifdef MAXPW
if (sz > MAXPW) sz = MAXPW;
#endif
if (*pw == NULL) { /* reallocate if no address */
void *tmp = realloc (*pw, sz * sizeof **pw);
if (!tmp)
return -1;
memset (tmp, 0, sz); /* initialize memory to 0 */
*pw = tmp;
}
size_t idx = 0; /* index, number of chars in read */
int c = 0;
struct termios old_kbd_mode; /* orig keyboard settings */
struct termios new_kbd_mode;
if (tcgetattr (0, &old_kbd_mode)) { /* save orig settings */
fprintf (stderr, "%s() error: tcgetattr failed.\n", __func__);
return -1;
} /* copy old to new */
memcpy (&new_kbd_mode, &old_kbd_mode, sizeof(struct termios));
new_kbd_mode.c_lflag &= ~(ICANON | ECHO); /* new kbd flags */
new_kbd_mode.c_cc[VTIME] = 0;
new_kbd_mode.c_cc[VMIN] = 1;
if (tcsetattr (0, TCSANOW, &new_kbd_mode)) {
fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__);
return -1;
}
/* read chars from fp, mask if valid char specified */
while (((c = fgetc (fp)) != '\n' && c != EOF && idx < sz - 1) ||
(idx == sz - 1 && c == 127))
{
if (c != 127) {
if (31 < mask && mask < 127) /* valid ascii char */
fputc (mask, stdout);
(*pw)[idx++] = c;
}
else if (idx > 0) { /* handle backspace (del) */
if (31 < mask && mask < 127) {
fputc (0x8, stdout);
fputc (' ', stdout);
fputc (0x8, stdout);
}
(*pw)[--idx] = 0;
}
}
(*pw)[idx] = 0; /* null-terminate */
/* reset original keyboard */
if (tcsetattr (0, TCSANOW, &old_kbd_mode)) {
fprintf (stderr, "%s() error: tcsetattr failed.\n", __func__);
return -1;
}
if (idx == sz - 1 && c != '\n') /* warn if pw truncated */
fprintf (stderr, " (%s() warning: truncated at %zu chars.)\n",
__func__, sz - 1);
return idx; /* number of chars in passwd */
}
Un programme simple montrant l'utilisation serait le suivant. Si vous utilisez un tableau statique de caractères pour conserver le mot de passe, assurez-vous simplement qu'un pointeur est passé à la fonction.
int main (void ) {
char pw[MAXPW] = {0};
char *p = pw;
FILE *fp = stdin;
ssize_t nchr = 0;
printf ( "\n Enter password: ");
nchr = getpasswd (&p, MAXPW, '*', fp);
printf ("\n you entered : %s (%zu chars)\n", p, nchr);
printf ( "\n Enter password: ");
nchr = getpasswd (&p, MAXPW, 0, fp);
printf ("\n you entered : %s (%zu chars)\n\n", p, nchr);
return 0;
}
Exemple de sortie
$ ./bin/getpasswd2
Enter password: ******
you entered : 123456 (6 chars)
Enter password:
you entered : abcdef (6 chars)
La fonctionnalité de getch
(qui est une fonction Windows non standard) peut être émulée avec ce code:
#include <termios.h>
#include <unistd.h>
int getch() {
struct termios oldt, newt;
int ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
Notez que votre approche n'est pas parfaite - il vaut mieux utiliser quelque chose comme ncurses ou une autre bibliothèque de terminaux pour gérer ces choses.
Vous pouvez créer votre propre fonction getch()
sous Linux de cette manière.
int getch() {
struct termios oldtc, newtc;
int ch;
tcgetattr(STDIN_FILENO, &oldtc);
newtc = oldtc;
newtc.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newtc);
ch=getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldtc);
return ch;
}
Code de démonstration:
int main(int argc, char **argv) {
int ch;
printf("Press x to exit.\n\n");
for (;;) {
ch = getch();
printf("ch = %c (%d)\n", ch, ch);
if(ch == 'x')
break;
}
return 0;
}
Votre méthode est correcte, mais vous devrez désactiver l'écho du terminal pendant la saisie du mot de passe:
#include <sgtty.h>
void echo_off()
{
struct sgttyb state;
(void)ioctl(0, (int)TIOCGETP, (char *)&state);
state.sg_flags &= ~ECHO;
(void)ioctl(0, (int)TIOCSETP, (char *)&state);
}
void echo_on()
{
struct sgttyb state;
(void)ioctl(0, (int)TIOCGETP, (char *)&state);
state.sg_flags |= ECHO;
(void)ioctl(0, (int)TIOCSETP, (char *)&state);
}
Au lieu de getch()
, pourquoi ne pas simplement utiliser getc()
à la place?
#include <termios.h>
#include <stdio.h>
static struct termios old, new;
void initTermios(int echo) {
tcgetattr(0, &old);
new = old;
new.c_lflag &= ~ICANON;
new.c_lflag &= echo ? ECHO : ~ECHO;
tcsetattr(0, TCSANOW, &new);
}
void resetTermios(void) {
tcsetattr(0, TCSANOW, &old);
}
char getch_(int echo) {
char ch;
initTermios(echo);
ch = getchar();
resetTermios();
return ch;
}
char getch(void) {
return getch_(0);
}
int main(void) {
char c;
printf("(getch example) please type a letter...");
c = getch();
printf("\nYou typed: %c\n", c);
return 0;
}
Copiez simplement ces extraits et utilisez-les. J'espère que cela a aidé
Merci à vous tous dont l'aide et le soutien pour résoudre mon problème. Je trouve le meilleur moyen de cacher mon mot de passe sous Linux qui me convient le mieux. Pour utiliser la fonction getpass (). Il suffit d'inclure le fichier "unistd.h".
syntex de la fonction getpass:
char * getpass (const char * Prompt)
Paramètres: Invite: pointeur de chaîne à imprimer lors de la demande de mot de passe
Valeur de retour: pointeur de chaîne du mot de passe
Exemple:
#include <stdio.h>
#include <unistd.h>
int main()
{
char *password; // password string pointer
password = getpass("Enter Password: "); // get a password
printf("%s\n",password); // this is just for conformation
// that password stored successfully
return 1;
}
sortie:
Entrer le mot de passe:
heet
Vous pouvez utiliser ncurses.h s'il n'est pas nécessaire d'être portable sur Windows pour cela, mais voici une sorte de version plus "portable":
S'il n'est pas nécessaire d'être portable, indiquez-nous une solution ncurses
portablegetch.h
/*portablegetch.h*/
#ifndef PGETCH
#define PGETCH
#ifdef __unix__
#include <termios.h>
#include <unistd.h>
static struct termios n_term;
static struct termios o_term;
static int
cbreak(int fd)
{
if((tcgetattr(fd, &o_term)) == -1)
return -1;
n_term = o_term;
n_term.c_lflag = n_term.c_lflag & ~(ECHO|ICANON);
n_term.c_cc[VMIN] = 1;
n_term.c_cc[VTIME]= 0;
if((tcsetattr(fd, TCSAFLUSH, &n_term)) == -1)
return -1;
return 1;
}
int
getch()
{
int cinput;
if(cbreak(STDIN_FILENO) == -1) {
fprintf(stderr, "cbreak failure, exiting \n");
exit(EXIT_FAILURE);
}
cinput = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &o_term);
return cinput;
}
#Elif _MSC_VER || __WIN32__ || __MS_DOS__
#include <conio.h>
#endif
#endif
Et le fichier c
que.c
#include <stdio.h>
#include <stdlib.h>
#include "portablegetch.h"
int
main(int argc, char **argv)
{
int input;
printf("Please Enter your Password:\t");
while(( input=getch() ) != '\n')
printf("*");
printf("\n");
return EXIT_SUCCESS;
}
Cela devrait correspondre à votre problème.
J'espère que ça t'as aidé.
Malheureusement, dans la bibliothèque standard C, il n'y a pas une telle fonction prête à l'emploi. Peut-être dans une bibliothèque tierce.
Une option consiste à utiliser des séquences d'échappement ANSI pour définir la couleur d'arrière-plan sur la couleur de premier plan dans la console pour masquer le mot de passe. Essayez ce lien .
En C, vous pouvez utiliser la fonction getpasswd()
qui fait à peu près la même chose que stty
dans Shell, exemple:
#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
int main()
{
char acct[80], password[80];
printf(“Account: “);
fgets(acct, 80, stdin);
acct[strlen(acct)-1] = 0; /* remove carriage return */
strncpy(password, getpass(“Password: “), 80);
printf(“You entered acct %s and pass %s\n”, acct, password);
return 0;
}
Voici un script Shell équivalent qui utilise stty
(qui modifie les paramètres de votre tty
):
save_state=$(stty -g)
/bin/echo -n “Account: “
read acct
/bin/echo -n “Password: “
stty -echo
read password # this won’t echo
stty “$save_state”
echo “”
echo account = $acct and password = $password
Source: Comment puis-je lire un mot de passe sans l'écho en C?
homme getpass
Cette fonction est obsolète. Ne l'utilise pas. Si vous souhaitez lire l'entrée sans que l'écho du terminal ne soit activé, consultez la description de l'indicateur ECHO dans termios (3)
# include <termios.h>
# include <unistd.h> /* needed for STDIN_FILENO which is an int file descriptor */
struct termios tp, save;
tcgetattr( STDIN_FILENO, &tp); /* get existing terminal properties */
save = tp; /* save existing terminal properties */
tp.c_lflag &= ~ECHO; /* only cause terminal echo off */
tcsetattr( STDIN_FILENO, TCSAFLUSH, &tp ); /* set terminal settings */
/*
now input by user in terminal will not be displayed
and cursor will not move
*/
tcsetattr( STDIN_FILENO, TCSANOW, &save); /* restore original terminal settings */
Si vous remarquez, la plupart des distributions Linux actuelles ne masquent pas un mot de passe avec des astérisques. Cela divulgue la longueur du mot de passe, ce qui n'est aucunement bénéfique. Il est plus facile et préférable de simplement faire en sorte que le curseur ne bouge pas lorsqu'un mot de passe est saisi. Si, pour une raison quelconque, vous avez besoin d'un *
pour être imprimé pour chaque caractère tapé, vous devrez alors saisir chaque pression de touche avant de frapper Enter
et cela a toujours été problématique.
En scannant les personnages, vous pouvez les mettre dans un tampon. Vous devez également écrire du code si vous appuyez sur la touche de retour arrière et corriger correctement le mot de passe inséré.
Voici un code que j'ai écrit avec les malédictions. Compiler avec gcc file.c -o pass_prog -lcurses
#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#define ENOUGH_SIZE 256
#define ECHO_ON 1
#define ECHO_OFF 0
#define BACK_SPACE 127
char *my_getpass (int echo_state);
int main (void)
{
char *pass;
initscr ();
printw ("Enter Password: ");
pass = my_getpass (ECHO_ON);
printw ("\nEntered Password: %s", pass);
refresh ();
getch ();
endwin ();
return 0;
}
char *my_getpass (int echo_state)
{
char *pass, c;
int i=0;
pass = malloc (sizeof (char) * ENOUGH_SIZE);
if (pass == NULL)
{
perror ("Exit");
exit (1);
}
cbreak ();
noecho ();
while ((c=getch()) != '\n')
{
if (c == BACK_SPACE)
{
/* Do not let the buffer underflow */
if (i > 0)
{
i--;
if (echo_state == ECHO_ON)
printw ("\b \b");
}
}
else if (c == '\t')
; /* Ignore tabs */
else
{
pass[i] = c;
i = (i >= ENOUGH_SIZE) ? ENOUGH_SIZE - 1 : i+1;
if (echo_state == ECHO_ON)
printw ("*");
}
}
echo ();
nocbreak ();
/* Terminate the password string with NUL */
pass[i] = '\0';
endwin ();
return pass;
}