18.10. Canonical ModeSection 18.3 that the following characters are interpreted as end of line in canonical mode: NL, EOL, EOL2, and EOF. Also, recall from Section 18.5 that if ICRNL is set and if IGNCR is not set, then the CR character also terminates a line, since it acts just like the NL character.Realize that of these five line delimiters, one (EOF) is discarded by the terminal driver when it's processed. The other four are returned to the caller as the last character of the line. Examplegetpass FunctionWe now show the function getpass, which reads a password of some type from the user at a terminal. This function is called by the login(1) and crypt(1) programs. To read the password, the function must turn off echoing, but it can leave the terminal in canonical mode, as whatever we type as the password forms a complete line. Chapter 3), but we would have to simulate the getc function using read. The program in Figure 18.18 calls getpass and prints what we enter to let us verify that the ERASE and KILL characters work (as they should in canonical mode).Whenever a program that calls getpass is done with the cleartext password, the program should zero it out in memory, just to be safe. If the program were to generate a core file that others might be able to read or if some other process were somehow able to read our memory, they might be able to read the cleartext password. (By "cleartext," we mean the password that we type at the prompt that is printed by getpass. Most UNIX system programs then modify this cleartext password into an "encrypted" password. The field pw_passwd in the password file, for example, contains the encrypted password, not the cleartext password.) Figure 18.17. Implementation of getpass function#include <signal.h> #include <stdio.h> #include <termios.h> #define MAX_PASS_LEN 8 /* max #chars for user to enter */ char * getpass(const char *prompt) { static char buf[MAX_PASS_LEN + 1]; /* null byte at end */ char *ptr; sigset_t sig, osig; struct termios ts, ots; FILE *fp; int c; if ((fp = fopen(ctermid(NULL), "r+")) == NULL) return(NULL); setbuf(fp, NULL); sigemptyset(&sig); sigaddset(&sig, SIGINT); /* block SIGINT */ sigaddset(&sig, SIGTSTP); /* block SIGTSTP */ sigprocmask(SIG_BLOCK, &sig, &osig); /* and save mask */ tcgetattr(fileno(fp), &ts); /* save tty state */ ots = ts; /* structure copy */ ts.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); tcsetattr(fileno(fp), TCSAFLUSH, &ts); fputs(prompt, fp); ptr = buf; while ((c = getc(fp)) != EOF && c != '\n') if (ptr < &buf[MAX_PASS_LEN]) *ptr++ = c; *ptr = 0; /* null terminate */ putc('\n', fp); /* we echo a newline */ tcsetattr(fileno(fp), TCSAFLUSH, &ots); /* restore TTY state */ sigprocmask(SIG_SETMASK, &osig, NULL); /* restore mask */ fclose(fp); /* done with /dev/tty */ return(buf); } Figure 18.18. Call the getpass function#include "apue.h" char *getpass(const char *); int main(void) { char *ptr; if ((ptr = getpass("Enter password:")) == NULL) err_sys("getpass error"); printf("password: %s\n", ptr); /* now use password (probably encrypt it) ... */ while (*ptr != 0) *ptr++ = 0; /* zero it out when we're done with it */ exit(0); } |