Tanpa getch
mengandalkan dan menghindari getpass
yang sudah usang , pendekatan yang disarankan adalah menonaktifkan terminal ECHO melalui termios
menggunakan. Setelah beberapa pencarian untuk menemukan rutinitas kata sandi fleksibel kalengan, saya terkejut bahwa sangat sedikit untuk penggunaan yang berdiri sendiri dengan C. Daripada hanya mengkode ulang getch
dengan termios c_lflag
pilihan, pendekatan yang sedikit lebih umum hanya membutuhkan beberapa tambahan. Selain mengganti getch
rutinitas apa pun harus menerapkan panjang maksimum yang ditentukan untuk mencegah luapan, memotong jika pengguna mencoba masuk melebihi batas maksimum, dan memperingatkan jika pemotongan terjadi dengan cara tertentu.
Di bawah, penambahan akan memungkinkan membaca dari FILE *
apa saja aliran input, membatasi panjang ke panjang yang ditentukan, memberikan kemampuan pengeditan minimal (backspace) saat mengambil input, memungkinkan mask karakter ditentukan atau dinonaktifkan sepenuhnya, dan akhirnya mengembalikan panjang kata sandi yang dimasukkan. Peringatan ditambahkan saat kata sandi yang dimasukkan dipotong ke panjang maksimum atau yang ditentukan.
Semoga bermanfaat bagi orang lain dengan pertanyaan ini mencari solusi serupa:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#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 = (char*) 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 */
}
Program sederhana yang menunjukkan penggunaannya adalah sebagai berikut. Jika menggunakan array karakter statis untuk menyimpan kata sandi, pastikan pointer diteruskan ke fungsi.
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;
}
Contoh Keluaran
$ ./bin/getpasswd2
Enter password: ******
you entered : 123456 (6 chars)
Enter password:
you entered : abcdef (6 chars)
Di dunia Linux, penyamaran biasanya tidak dilakukan dengan tanda bintang, biasanya gema dimatikan dan terminal menampilkan kosong E.g. jika Anda menggunakan su
atau masuk ke terminal virtual dll.
Ada fungsi perpustakaan untuk menangani mendapatkan kata sandi, itu tidak akan menutupi kata sandi dengan tanda bintang tetapi akan menonaktifkan gema kata sandi ke terminal. Saya menarik ini dari buku linux yang saya miliki. Saya yakin ini bagian dari standar posix
#include <unistd.h> char *getpass(const char *prompt); /*Returns pointer to statically allocated input password string on success, or NULL on error*/
Fungsi getpass() pertama-tama menonaktifkan gema dan semua pemrosesan karakter khusus terminal (seperti karakter interupsi, biasanyaControl-C).
Itu kemudian mencetak string yang ditunjuk oleh prompt, dan membaca baris input, mengembalikan string input yang diakhiri null dengan baris baru yang tertinggal dihapus, sebagai hasil fungsinya.
Pencarian google untuk getpass() memiliki referensi ke implementasi GNU (harus ada di sebagian besar distro linux) dan beberapa kode contoh untuk mengimplementasikan milik Anda sendiri jika perlu
http://www.gnu.org/s/hello/manual/libc/getpass.html
Contoh mereka untuk menggulirkan milik Anda sendiri:
#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;
}
Jika perlu, Anda dapat menggunakan ini sebagai dasar untuk memodifikasinya agar menampilkan tanda bintang.