1 // PAM module for two-factor authentication.
2 //
3 // Copyright 2010 Google Inc.
4 // Author: Markus Gutschke
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 //
10 //      http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 #include "config.h"
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <pwd.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <syslog.h>
30 #include <time.h>
31 #include <unistd.h>
32 
33 #ifdef HAVE_SYS_FSUID_H
34 // We much rather prefer to use setfsuid(), but this function is unfortunately
35 // not available on all systems.
36 #include <sys/fsuid.h>
37 #endif
38 
39 #ifndef PAM_EXTERN
40 #define PAM_EXTERN
41 #endif
42 
43 #if !defined(LOG_AUTHPRIV) && defined(LOG_AUTH)
44 #define LOG_AUTHPRIV LOG_AUTH
45 #endif
46 
47 #define PAM_SM_AUTH
48 #include <security/pam_appl.h>
49 #include <security/pam_modules.h>
50 
51 #include "base32.h"
52 #include "hmac.h"
53 #include "sha1.h"
54 #include "util.h"
55 
56 #define MODULE_NAME   "pam_google_authenticator"
57 #define SECRET        "~/.google_authenticator"
58 #define CODE_PROMPT   "Verification code: "
59 #define PWCODE_PROMPT "Password & verification code: "
60 
61 typedef struct Params {
62   const char *secret_filename_spec;
63   const char *authtok_prompt;
64   enum { NULLERR=0, NULLOK, SECRETNOTFOUND } nullok;
65   int        noskewadj;
66   int        echocode;
67   int        fixed_uid;
68   int        no_increment_hotp;
69   uid_t      uid;
70   enum { PROMPT = 0, TRY_FIRST_PASS, USE_FIRST_PASS } pass_mode;
71   int        forward_pass;
72   int        debug;
73   int        no_strict_owner;
74   int        allowed_perm;
75   time_t     grace_period;
76   int        allow_readonly;
77 } Params;
78 
79 static char oom;
80 
81 static const char* nobody = "nobody";
82 
83 #if defined(DEMO) || defined(TESTING)
84 static char* error_msg = NULL;
85 
86 const char *get_error_msg(void) __attribute__((visibility("default")));
get_error_msg(void)87 const char *get_error_msg(void) {
88   if (!error_msg) {
89     return "";
90   }
91   return error_msg;
92 }
93 #endif
94 
log_message(int priority,pam_handle_t * pamh,const char * format,...)95 static void log_message(int priority, pam_handle_t *pamh,
96                         const char *format, ...) {
97   char *service = NULL;
98   if (pamh)
99     pam_get_item(pamh, PAM_SERVICE, (void *)&service);
100   if (!service)
101     service = "";
102 
103   char logname[80];
104   snprintf(logname, sizeof(logname), "%s(" MODULE_NAME ")", service);
105 
106   va_list args;
107   va_start(args, format);
108 #if !defined(DEMO) && !defined(TESTING)
109   openlog(logname, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
110   vsyslog(priority, format, args);
111   closelog();
112 #else
113   if (!error_msg) {
114     error_msg = strdup("");
115   }
116   {
117     char buf[1000];
118     vsnprintf(buf, sizeof buf, format, args);
119     const int newlen = strlen(error_msg) + 1 + strlen(buf) + 1;
120     char* n = malloc(newlen);
121     if (n) {
122       snprintf(n, newlen, "%s%s%s", error_msg, strlen(error_msg)?"\n":"",buf);
123       free(error_msg);
124       error_msg = n;
125     } else {
126       fprintf(stderr, "Failed to malloc %d bytes for log data.\n", newlen);
127     }
128   }
129 #endif
130 
131   va_end(args);
132 
133   if (priority == LOG_EMERG) {
134     // Something really bad happened. There is no way we can proceed safely.
135     _exit(1);
136   }
137 }
138 
converse(pam_handle_t * pamh,int nargs,PAM_CONST struct pam_message ** message,struct pam_response ** response)139 static int converse(pam_handle_t *pamh, int nargs,
140                     PAM_CONST struct pam_message **message,
141                     struct pam_response **response) {
142   struct pam_conv *conv;
143   int retval = pam_get_item(pamh, PAM_CONV, (void *)&conv);
144   if (retval != PAM_SUCCESS) {
145     return retval;
146   }
147   return conv->conv(nargs, message, response, conv->appdata_ptr);
148 }
149 
get_user_name(pam_handle_t * pamh,const Params * params)150 static const char *get_user_name(pam_handle_t *pamh, const Params *params) {
151   // Obtain the user's name
152   const char *username;
153   if (pam_get_user(pamh, &username, NULL) != PAM_SUCCESS ||
154       !username || !*username) {
155     log_message(LOG_ERR, pamh,
156                 "pam_get_user() failed to get a user name"
157                 " when checking verification code");
158     return NULL;
159   }
160   if (params->debug) {
161     log_message(LOG_INFO, pamh, "debug: start of google_authenticator for \"%s\"", username);
162   }
163   return username;
164 }
165 
166 /*
167  * Return rhost as a string. Return value must not be free()ed.
168  * Returns NULL if PAM_RHOST is not known.
169  */
170 static const char *
get_rhost(pam_handle_t * pamh,const Params * params)171 get_rhost(pam_handle_t *pamh, const Params *params) {
172   // Get the remote host
173   PAM_CONST void *rhost;
174   if (pam_get_item(pamh, PAM_RHOST, &rhost) != PAM_SUCCESS) {
175     log_message(LOG_ERR, pamh, "pam_get_rhost() failed to get the remote host");
176     return NULL;
177   }
178   if (params->debug) {
179     log_message(LOG_INFO, pamh, "debug: google_authenticator for host \"%s\"",
180                 rhost);
181   }
182   return (const char *)rhost;
183 }
184 
185 static size_t
getpwnam_buf_max_size()186 getpwnam_buf_max_size()
187 {
188 #ifdef _SC_GETPW_R_SIZE_MAX
189   const ssize_t len = sysconf(_SC_GETPW_R_SIZE_MAX);
190   if (len <= 0) {
191     return 4096;
192   }
193   return len;
194 #else
195   return 4096;
196 #endif
197 }
198 
get_secret_filename(pam_handle_t * pamh,const Params * params,const char * username,uid_t * uid)199 static char *get_secret_filename(pam_handle_t *pamh, const Params *params,
200                                  const char *username, uid_t *uid) {
201   if (!username) {
202     return NULL;
203   }
204 
205   // Check whether the administrator decided to override the default location
206   // for the secret file.
207   const char *spec = params->secret_filename_spec
208     ? params->secret_filename_spec : SECRET;
209 
210   // Obtain the user's id and home directory
211   // NOTE: These variables need to be here because of their lifetimes.
212   struct passwd *pw = NULL;     // Used
213   struct passwd pwbuf;          // Here because `pw` points into it.
214   char *buf = NULL;             // Here because `pw` members use it.
215   char *secret_filename = NULL; // Here because goto jumps.
216 
217   if (!params->fixed_uid) {
218     const int len = getpwnam_buf_max_size();
219     buf = malloc(len);
220     *uid = -1;
221     if (buf == NULL) {
222       log_message(LOG_ERR, pamh, "Short (%d) mem allocation failed", len);
223       goto errout;
224     }
225 
226     const int rc = getpwnam_r(username, &pwbuf, buf, len, &pw);
227     if (rc) {
228       log_message(LOG_ERR, pamh, "getpwnam_r(\"%s\")!=0: %d", username, rc);
229       goto errout;
230     }
231 
232     if (!pw) {
233       log_message(LOG_ERR, pamh, "user(\"%s\") not found", username);
234       goto errout;
235     }
236 
237     if (!pw->pw_dir) {
238       log_message(LOG_ERR, pamh, "user(\"%s\") has no home dir", username);
239       goto errout;
240     }
241 
242     if (*pw->pw_dir != '/') {
243       log_message(LOG_ERR, pamh, "User \"%s\" home dir not absolute", username);
244       goto errout;
245     }
246   }
247 
248   // Expand filename specification to an actual filename.
249   if ((secret_filename = strdup(spec)) == NULL) {
250     log_message(LOG_ERR, pamh, "Short (%d) mem allocation failed", strlen(spec));
251     goto errout;
252   }
253   int allow_tilde = 1;
254   for (int offset = 0; secret_filename[offset];) {
255     char *cur = secret_filename + offset;
256     char *var = NULL;
257     size_t var_len = 0;
258     const char *subst = NULL;
259     if (allow_tilde && *cur == '~') {
260       var_len = 1;
261       if (!pw) {
262         log_message(LOG_ERR, pamh,
263                     "Home dir in 'secret' not implemented when 'user' set");
264         goto errout;
265       }
266       subst = pw->pw_dir;
267       var = cur;
268     } else if (secret_filename[offset] == '$') {
269       if (!memcmp(cur, "${HOME}", 7)) {
270         var_len = 7;
271         if (!pw) {
272           log_message(LOG_ERR, pamh,
273                       "Home dir in 'secret' not implemented when 'user' set");
274           goto errout;
275         }
276         subst = pw->pw_dir;
277         var = cur;
278       } else if (!memcmp(cur, "${USER}", 7)) {
279         var_len = 7;
280         subst = username;
281         var = cur;
282       }
283     }
284     if (var) {
285       const size_t subst_len = strlen(subst);
286       if (subst_len > 1000000) {
287         log_message(LOG_ERR, pamh, "Unexpectedly large path name: %d", subst_len);
288         goto errout;
289       }
290       const int varidx = var - secret_filename;
291       char *resized = realloc(secret_filename,
292                               strlen(secret_filename) + subst_len + 1);
293       if (!resized) {
294         log_message(LOG_ERR, pamh, "Short mem allocation failed");
295         goto errout;
296       }
297       var = resized + varidx;
298       secret_filename = resized;
299       memmove(var + subst_len, var + var_len, strlen(var + var_len) + 1);
300       memmove(var, subst, subst_len);
301       offset = var + subst_len - resized;
302       allow_tilde = 0;
303     } else {
304       allow_tilde = *cur == '/';
305       ++offset;
306     }
307   }
308 
309   *uid = params->fixed_uid ? params->uid : pw->pw_uid;
310   free(buf);
311   return secret_filename;
312 
313 errout:
314   free(secret_filename);
315   free(buf);
316   return NULL;
317 }
318 
setuser(int uid)319 static int setuser(int uid) {
320 #ifdef HAVE_SETFSUID
321   // The semantics for setfsuid() are a little unusual. On success, the
322   // previous user id is returned. On failure, the current user id is returned.
323   int old_uid = setfsuid(uid);
324   if (uid != setfsuid(uid)) {
325     setfsuid(old_uid);
326     return -1;
327   }
328 #else
329 #ifdef linux
330 #error "Linux should have setfsuid(). Refusing to build."
331 #endif
332   int old_uid = geteuid();
333   if (old_uid != uid && seteuid(uid)) {
334     return -1;
335   }
336 #endif
337   return old_uid;
338 }
339 
setgroup(int gid)340 static int setgroup(int gid) {
341 #ifdef HAVE_SETFSGID
342   // The semantics of setfsgid() are a little unusual. On success, the
343   // previous group id is returned. On failure, the current groupd id is
344   // returned.
345   int old_gid = setfsgid(gid);
346   if (gid != setfsgid(gid)) {
347     setfsgid(old_gid);
348     return -1;
349   }
350 #else
351   int old_gid = getegid();
352   if (old_gid != gid && setegid(gid)) {
353     return -1;
354   }
355 #endif
356   return old_gid;
357 }
358 
359 // Drop privileges and return 0 on success.
drop_privileges(pam_handle_t * pamh,const char * username,int uid,int * old_uid,int * old_gid)360 static int drop_privileges(pam_handle_t *pamh, const char *username, int uid,
361                            int *old_uid, int *old_gid) {
362   // Try to become the new user. This might be necessary for NFS mounted home
363   // directories.
364 
365   // First, look up the user's default group
366   #ifdef _SC_GETPW_R_SIZE_MAX
367   int len = sysconf(_SC_GETPW_R_SIZE_MAX);
368   if (len <= 0) {
369     len = 4096;
370   }
371   #else
372   int len = 4096;
373   #endif
374   char *buf = malloc(len);
375   if (!buf) {
376     log_message(LOG_ERR, pamh, "Out of memory");
377     return -1;
378   }
379   struct passwd pwbuf, *pw;
380   if (getpwuid_r(uid, &pwbuf, buf, len, &pw) || !pw) {
381     log_message(LOG_ERR, pamh, "Cannot look up user id %d", uid);
382     free(buf);
383     return -1;
384   }
385   gid_t gid = pw->pw_gid;
386   free(buf);
387 
388   int gid_o = setgroup(gid);
389   int uid_o = setuser(uid);
390   if (uid_o < 0) {
391     if (gid_o >= 0) {
392       if (setgroup(gid_o) < 0 || setgroup(gid_o) != gid_o) {
393         // Inform the caller that we were unsuccessful in resetting the group.
394         *old_gid = gid_o;
395       }
396     }
397     log_message(LOG_ERR, pamh, "Failed to change user id to \"%s\"",
398                 username);
399     return -1;
400   }
401   if (gid_o < 0 && (gid_o = setgroup(gid)) < 0) {
402     // In most typical use cases, the PAM module will end up being called
403     // while uid=0. This allows the module to change to an arbitrary group
404     // prior to changing the uid. But there are many ways that PAM modules
405     // can be invoked and in some scenarios this might not work. So, we also
406     // try changing the group _after_ changing the uid. It might just work.
407     if (setuser(uid_o) < 0 || setuser(uid_o) != uid_o) {
408       // Inform the caller that we were unsuccessful in resetting the uid.
409       *old_uid = uid_o;
410     }
411     log_message(LOG_ERR, pamh,
412                 "Failed to change group id for user \"%s\" to %d", username,
413                 (int)gid);
414     return -1;
415   }
416 
417   *old_uid = uid_o;
418   *old_gid = gid_o;
419   return 0;
420 }
421 
422 // open secret file, return 0 on success.
open_secret_file(pam_handle_t * pamh,const char * secret_filename,struct Params * params,const char * username,int uid,struct stat * orig_stat)423 static int open_secret_file(pam_handle_t *pamh, const char *secret_filename,
424                             struct Params *params, const char *username,
425                             int uid, struct stat *orig_stat) {
426   // Try to open "~/.google_authenticator"
427   const int fd = open(secret_filename, O_RDONLY);
428   if (fd < 0 ||
429       fstat(fd, orig_stat) < 0) {
430     if (params->nullok != NULLERR && errno == ENOENT) {
431       // The user doesn't have a state file, but the administrator said
432       // that this is OK. We still return an error from open_secret_file(),
433       // but we remember that this was the result of a missing state file.
434       params->nullok = SECRETNOTFOUND;
435     } else {
436       log_message(LOG_ERR, pamh, "Failed to read \"%s\" for \"%s\": %s",
437                   secret_filename, username, strerror(errno));
438     }
439  error:
440     if (fd >= 0) {
441       close(fd);
442     }
443     return -1;
444   }
445 
446   if (params->debug) {
447     log_message(LOG_INFO, pamh,
448                 "debug: Secret file permissions are %04o."
449                 " Allowed permissions are %04o",
450                 orig_stat->st_mode & 03777, params->allowed_perm);
451   }
452 
453   // Check permissions on "~/.google_authenticator".
454   if (!S_ISREG(orig_stat->st_mode)) {
455     log_message(LOG_ERR, pamh, "Secret file \"%s\" is not a regular file",
456                 secret_filename);
457     goto error;
458   }
459   if (orig_stat->st_mode & 03777 & ~params->allowed_perm) {
460     log_message(LOG_ERR, pamh,
461                 "Secret file \"%s\" permissions (%04o)"
462                 " are more permissive than %04o", secret_filename,
463                 orig_stat->st_mode & 03777, params->allowed_perm);
464     goto error;
465   }
466 
467   if (!params->no_strict_owner && (orig_stat->st_uid != (uid_t)uid)) {
468     char buf[80];
469     if (params->fixed_uid) {
470       snprintf(buf, sizeof buf, "user id %d", params->uid);
471       username = buf;
472     }
473     log_message(LOG_ERR, pamh,
474                 "Secret file \"%s\" must be owned by \"%s\"",
475                 secret_filename, username);
476     goto error;
477   }
478 
479   // Sanity check for file length
480   if (orig_stat->st_size < 1 || orig_stat->st_size > 64*1024) {
481     log_message(LOG_ERR, pamh,
482                 "Invalid file size for \"%s\"", secret_filename);
483     goto error;
484   }
485 
486   return fd;
487 }
488 
489 // Read secret file contents.
490 // If there's an error the file is closed, NULL is returned, and errno set.
read_file_contents(pam_handle_t * pamh,const Params * params,const char * secret_filename,int * fd,off_t filesize)491 static char *read_file_contents(pam_handle_t *pamh,
492                                 const Params *params,
493                                 const char *secret_filename, int *fd,
494                                 off_t filesize) {
495   // Arbitrary limit to prevent integer overflow.
496   if (filesize > 1000000) {
497     close(*fd);
498     errno = E2BIG;
499     return NULL;
500   }
501 
502   // Read file contents
503   char *buf = malloc(filesize + 1);
504   if (!buf) {
505     log_message(LOG_ERR, pamh, "Failed to malloc %d+1", filesize);
506     goto out;
507   }
508 
509   if (filesize != read(*fd, buf, filesize)) {
510     log_message(LOG_ERR, pamh, "Could not read \"%s\"", secret_filename);
511     goto out;
512   }
513   close(*fd);
514   *fd = -1;
515 
516   // The rest of the code assumes that there are no NUL bytes in the file.
517   if (memchr(buf, 0, filesize)) {
518     log_message(LOG_ERR, pamh, "Invalid file contents in \"%s\"",
519                 secret_filename);
520     goto out;
521   }
522 
523   // Terminate the buffer with a NUL byte.
524   buf[filesize] = '\000';
525 
526   if(params->debug) {
527     log_message(LOG_INFO, pamh, "debug: \"%s\" read", secret_filename);
528   }
529   return buf;
530 
531 out:
532   // If we have any data, erase it.
533   if (buf) {
534     explicit_bzero(buf, filesize);
535   }
536   free(buf);
537   if (*fd >= 0) {
538     close(*fd);
539     *fd = -1;
540   }
541   return NULL;
542 }
543 
is_totp(const char * buf)544 static int is_totp(const char *buf) {
545   return !!strstr(buf, "\" TOTP_AUTH");
546 }
547 
548 // Wrap write() making sure that partial writes don't break everything.
549 // Return 0 on success, errno otherwise.
550 static int
full_write(int fd,const char * buf,size_t len)551 full_write(int fd, const char* buf, size_t len) {
552   const char* p = buf;
553   int errors = 0;
554   for (;;) {
555     const ssize_t left = len - (p - buf);
556     const ssize_t rc = write(fd, p, left);
557     if (rc == left) {
558       return 0;
559     }
560     if (rc < 0) {
561       switch (errno) {
562       case EAGAIN:
563       case EINTR:
564         if (errors++ < 3) {
565           continue;
566         }
567       }
568       return errno;
569     }
570     p += rc;
571   }
572 }
573 
574 // Safely overwrite the old secret file.
575 // Return 0 on success, errno otherwise.
write_file_contents(pam_handle_t * pamh,const Params * params,const char * secret_filename,struct stat * orig_stat,const char * buf)576 static int write_file_contents(pam_handle_t *pamh,
577                                const Params *params,
578                                const char *secret_filename,
579                                struct stat *orig_stat,
580                                const char *buf) {
581   int err = 0;
582   int fd = -1;
583   const size_t fnlength = strlen(secret_filename) + 1 + 6 + 1;
584 
585   char *tmp_filename = malloc(fnlength);
586   if (tmp_filename == NULL) {
587     err = errno;
588     goto cleanup;
589   }
590 
591   if (fnlength - 1 != snprintf(tmp_filename, fnlength,
592                                "%s~XXXXXX", secret_filename)) {
593     err = ERANGE;
594     goto cleanup;
595   }
596   const mode_t old_mask = umask(077);
597   fd = mkstemp(tmp_filename);
598   umask(old_mask);
599   if (fd < 0) {
600     err = errno;
601     log_message(LOG_ERR, pamh, "Failed to create tempfile \"%s\": %s",
602                 tmp_filename, strerror(err));
603 
604     // Couldn't open file; don't try to delete it later.
605     free(tmp_filename);
606     tmp_filename = NULL;
607     goto cleanup;
608   }
609   if (fchmod(fd, 0400)) {
610     err = errno;
611     goto cleanup;
612   }
613 
614   // Make sure the secret file is still the same. This prevents attackers
615   // from opening a lot of pending sessions and then reusing the same
616   // scratch code multiple times.
617   //
618   // (except for the brief race condition between this stat and the
619   // `rename` below)
620   {
621     struct stat sb;
622     if (stat(secret_filename, &sb) != 0) {
623       err = errno;
624       goto cleanup;
625     }
626 
627     if (sb.st_ino != orig_stat->st_ino ||
628         sb.st_size != orig_stat->st_size ||
629         sb.st_mtime != orig_stat->st_mtime) {
630       err = EAGAIN;
631       log_message(LOG_ERR, pamh,
632                   "Secret file \"%s\" changed while trying to use "
633                   "scratch code\n", secret_filename);
634       goto cleanup;
635     }
636   }
637 
638   // Write the new file contents.
639   if ((err = full_write(fd, buf, strlen(buf)))) {
640     goto cleanup;
641   }
642   if (fsync(fd)) {
643     err = errno;
644     goto cleanup;
645   }
646   if (close(fd)) {
647     err = errno;
648     goto cleanup;
649   }
650   fd = -1; // Prevent double-close.
651   if (rename(tmp_filename, secret_filename) != 0) {
652     err = errno;
653     goto cleanup;
654   }
655   free(tmp_filename);
656   tmp_filename = NULL; // Prevent unlink & double-free.
657 
658   if (params->debug) {
659     log_message(LOG_INFO, pamh, "debug: \"%s\" written", secret_filename);
660   }
661 
662 cleanup:
663   if (fd >= 0) {
664     close(fd);
665   }
666   if (tmp_filename) {
667     if (unlink(tmp_filename)) {
668       log_message(LOG_ERR, pamh, "Failed to delete tempfile \"%s\": %s",
669                   tmp_filename, strerror(errno));
670     }
671   }
672   free(tmp_filename);
673 
674   if (err) {
675     log_message(LOG_ERR, pamh, "Failed to update secret file \"%s\": %s",
676                 secret_filename, strerror(err));
677     return err;
678   }
679   return 0;
680 }
681 
682 // given secret file content (buf), extract the secret and base32 decode it.
683 //
684 // Return pointer to `malloc()`'d secret on success (caller frees),
685 // NULL on error. Length of secret stored in *secretLen.
get_shared_secret(pam_handle_t * pamh,const Params * params,const char * secret_filename,const char * buf,int * secretLen)686 static uint8_t *get_shared_secret(pam_handle_t *pamh,
687                                   const Params *params,
688                                   const char *secret_filename,
689                                   const char *buf, int *secretLen) {
690   if (!buf) {
691     return NULL;
692   }
693   // Decode secret key
694   const int base32Len = strcspn(buf, "\n");
695 
696   // Arbitrary limit to prevent integer overflow.
697   if (base32Len > 100000) {
698     return NULL;
699   }
700 
701   *secretLen = (base32Len*5 + 7)/8;
702   uint8_t *secret = malloc(base32Len + 1);
703   if (secret == NULL) {
704     *secretLen = 0;
705     return NULL;
706   }
707   memcpy(secret, buf, base32Len);
708   secret[base32Len] = '\000';
709   if ((*secretLen = base32_decode(secret, secret, base32Len)) < 1) {
710     log_message(LOG_ERR, pamh,
711                 "Could not find a valid BASE32 encoded secret in \"%s\"",
712                 secret_filename);
713     explicit_bzero(secret, base32Len);
714     free(secret);
715     return NULL;
716   }
717   memset(secret + *secretLen, 0, base32Len + 1 - *secretLen);
718 
719   if(params->debug) {
720     log_message(LOG_INFO, pamh, "debug: shared secret in \"%s\" processed", secret_filename);
721   }
722   return secret;
723 }
724 
725 #ifdef TESTING
726 static time_t current_time;
727 void set_time(time_t t) __attribute__((visibility("default")));
set_time(time_t t)728 void set_time(time_t t) {
729   current_time = t;
730 }
731 
get_time(void)732 static time_t get_time(void) {
733   return current_time;
734 }
735 #else
get_time(void)736 static time_t get_time(void) {
737   return time(NULL);
738 }
739 #endif
740 
comparator(const void * a,const void * b)741 static int comparator(const void *a, const void *b) {
742   return *(unsigned int *)a - *(unsigned int *)b;
743 }
744 
get_cfg_value(pam_handle_t * pamh,const char * key,const char * buf)745 static char *get_cfg_value(pam_handle_t *pamh, const char *key,
746                            const char *buf) {
747   const size_t key_len = strlen(key);
748   for (const char *line = buf; *line; ) {
749     const char *ptr;
750     if (line[0] == '"' && line[1] == ' ' && !strncmp(line+2, key, key_len) &&
751         (!*(ptr = line+2+key_len) || *ptr == ' ' || *ptr == '\t' ||
752          *ptr == '\r' || *ptr == '\n')) {
753       ptr += strspn(ptr, " \t");
754       size_t val_len = strcspn(ptr, "\r\n");
755       char *val = malloc(val_len + 1);
756       if (!val) {
757         log_message(LOG_ERR, pamh, "Out of memory");
758         return &oom;
759       } else {
760         memcpy(val, ptr, val_len);
761         val[val_len] = '\000';
762         return val;
763       }
764     } else {
765       line += strcspn(line, "\r\n");
766       line += strspn(line, "\r\n");
767     }
768   }
769   return NULL;
770 }
771 
set_cfg_value(pam_handle_t * pamh,const char * key,const char * val,char ** buf)772 static int set_cfg_value(pam_handle_t *pamh, const char *key, const char *val,
773                          char **buf) {
774   const size_t key_len = strlen(key);
775   char *start = NULL;
776   char *stop = NULL;
777 
778   // Find an existing line, if any.
779   for (char *line = *buf; *line; ) {
780     char *ptr;
781     if (line[0] == '"' && line[1] == ' ' && !strncmp(line+2, key, key_len) &&
782         (!*(ptr = line+2+key_len) || *ptr == ' ' || *ptr == '\t' ||
783          *ptr == '\r' || *ptr == '\n')) {
784       start = line;
785       stop  = start + strcspn(start, "\r\n");
786       stop += strspn(stop, "\r\n");
787       break;
788     } else {
789       line += strcspn(line, "\r\n");
790       line += strspn(line, "\r\n");
791     }
792   }
793 
794   // If no existing line, insert immediately after the first line.
795   if (!start) {
796     start  = *buf + strcspn(*buf, "\r\n");
797     start += strspn(start, "\r\n");
798     stop   = start;
799   }
800 
801   // Replace [start..stop] with the new contents.
802   const size_t val_len = strlen(val);
803   const size_t total_len = key_len + val_len + 4;
804   if (total_len <= stop - start) {
805     // We are decreasing out space requirements. Shrink the buffer and pad with
806     // NUL characters.
807     const size_t tail_len = strlen(stop);
808     memmove(start + total_len, stop, tail_len + 1);
809     memset(start + total_len + tail_len, 0, stop - start - total_len + 1);
810   } else {
811     // Must resize existing buffer. We cannot call realloc(), as it could
812     // leave parts of the buffer content in unused parts of the heap.
813     const size_t buf_len = strlen(*buf);
814     const size_t tail_len = buf_len - (stop - *buf);
815     char *resized = malloc(buf_len - (stop - start) + total_len + 1);
816     if (!resized) {
817       log_message(LOG_ERR, pamh, "Out of memory");
818       return -1;
819     }
820     memcpy(resized, *buf, start - *buf);
821     memcpy(resized + (start - *buf) + total_len, stop, tail_len + 1);
822     memset(*buf, 0, buf_len);
823     free(*buf);
824     start = start - *buf + resized;
825     *buf = resized;
826   }
827 
828   // Fill in new contents.
829   start[0] = '"';
830   start[1] = ' ';
831   memcpy(start + 2, key, key_len);
832   start[2+key_len] = ' ';
833   memcpy(start+3+key_len, val, val_len);
834   start[3+key_len+val_len] = '\n';
835 
836   // Check if there are any other occurrences of "value". If so, delete them.
837   for (char *line = start + 4 + key_len + val_len; *line; ) {
838     char *ptr;
839     if (line[0] == '"' && line[1] == ' ' && !strncmp(line+2, key, key_len) &&
840         (!*(ptr = line+2+key_len) || *ptr == ' ' || *ptr == '\t' ||
841          *ptr == '\r' || *ptr == '\n')) {
842       start = line;
843       stop = start + strcspn(start, "\r\n");
844       stop += strspn(stop, "\r\n");
845       size_t tail_len = strlen(stop);
846       memmove(start, stop, tail_len + 1);
847       memset(start + tail_len, 0, stop - start);
848       line = start;
849     } else {
850       line += strcspn(line, "\r\n");
851       line += strspn(line, "\r\n");
852     }
853   }
854 
855   return 0;
856 }
857 
step_size(pam_handle_t * pamh,const char * secret_filename,const char * buf)858 static int step_size(pam_handle_t *pamh, const char *secret_filename,
859                      const char *buf) {
860   const char *value = get_cfg_value(pamh, "STEP_SIZE", buf);
861   if (!value) {
862     // Default step size is 30.
863     return 30;
864   } else if (value == &oom) {
865     // Out of memory. This is a fatal error.
866     return 0;
867   }
868 
869   char *endptr;
870   errno = 0;
871   const int step = (int)strtoul(value, &endptr, 10);
872   if (errno || !*value || value == endptr ||
873       (*endptr && *endptr != ' ' && *endptr != '\t' &&
874        *endptr != '\n' && *endptr != '\r') ||
875       step < 1 || step > 60) {
876     free((void *)value);
877     log_message(LOG_ERR, pamh, "Invalid STEP_SIZE option in \"%s\"",
878                 secret_filename);
879     return 0;
880   }
881   free((void *)value);
882   return step;
883 }
884 
get_timestamp(pam_handle_t * pamh,const char * secret_filename,const char ** buf)885 static int get_timestamp(pam_handle_t *pamh, const char *secret_filename,
886                          const char **buf) {
887   const int step = step_size(pamh, secret_filename, *buf);
888   if (!step) {
889     return 0;
890   }
891   return get_time()/step;
892 }
893 
get_hotp_counter(pam_handle_t * pamh,const char * buf)894 static long get_hotp_counter(pam_handle_t *pamh, const char *buf) {
895   if (!buf) {
896     return -1;
897   }
898   const char *counter_str = get_cfg_value(pamh, "HOTP_COUNTER", buf);
899   if (counter_str == &oom) {
900     // Out of memory. This is a fatal error
901     return -1;
902   }
903 
904   long counter = 0;
905   if (counter_str) {
906     counter = strtol(counter_str, NULL, 10);
907   }
908   free((void *)counter_str);
909 
910   return counter;
911 }
912 
rate_limit(pam_handle_t * pamh,const char * secret_filename,int * updated,char ** buf)913 static int rate_limit(pam_handle_t *pamh, const char *secret_filename,
914                       int *updated, char **buf) {
915   const char *value = get_cfg_value(pamh, "RATE_LIMIT", *buf);
916   if (!value) {
917     // Rate limiting is not enabled for this account
918     return 0;
919   } else if (value == &oom) {
920     // Out of memory. This is a fatal error.
921     return -1;
922   }
923 
924   // Parse both the maximum number of login attempts and the time interval
925   // that we are looking at.
926   const char *endptr = value, *ptr;
927   int attempts, interval;
928   errno = 0;
929   if (((attempts = (int)strtoul(ptr = endptr, (char **)&endptr, 10)) < 1) ||
930       ptr == endptr ||
931       attempts > 100 ||
932       errno ||
933       (*endptr != ' ' && *endptr != '\t') ||
934       ((interval = (int)strtoul(ptr = endptr, (char **)&endptr, 10)) < 1) ||
935       ptr == endptr ||
936       interval > 3600 ||
937       errno) {
938     free((void *)value);
939     log_message(LOG_ERR, pamh, "Invalid RATE_LIMIT option. Check \"%s\".",
940                 secret_filename);
941     return -1;
942   }
943 
944   // Parse the time stamps of all previous login attempts.
945   const unsigned int now = get_time();
946   unsigned int *timestamps = malloc(sizeof(int));
947   if (!timestamps) {
948   oom:
949     free((void *)value);
950     log_message(LOG_ERR, pamh, "Out of memory");
951     return -1;
952   }
953   timestamps[0] = now;
954   int num_timestamps = 1;
955   while (*endptr && *endptr != '\r' && *endptr != '\n') {
956     unsigned int timestamp;
957     errno = 0;
958     if ((*endptr != ' ' && *endptr != '\t') ||
959         ((timestamp = (int)strtoul(ptr = endptr, (char **)&endptr, 10)),
960          errno) ||
961         ptr == endptr) {
962       free((void *)value);
963       free(timestamps);
964       log_message(LOG_ERR, pamh, "Invalid list of timestamps in RATE_LIMIT. "
965                   "Check \"%s\".", secret_filename);
966       return -1;
967     }
968     num_timestamps++;
969     unsigned int *tmp = (unsigned int *)realloc(timestamps,
970                                                 sizeof(int) * num_timestamps);
971     if (!tmp) {
972       free(timestamps);
973       goto oom;
974     }
975     timestamps = tmp;
976     timestamps[num_timestamps-1] = timestamp;
977   }
978   free((void *)value);
979   value = NULL;
980 
981   // Sort time stamps, then prune all entries outside of the current time
982   // interval.
983   qsort(timestamps, num_timestamps, sizeof(int), comparator);
984   int start = 0, stop = -1;
985   for (int i = 0; i < num_timestamps; ++i) {
986     if (timestamps[i] < now - interval) {
987       start = i+1;
988     } else if (timestamps[i] > now) {
989       break;
990     }
991     stop = i;
992   }
993 
994   // Error out, if there are too many login attempts.
995   int exceeded = 0;
996   if (stop - start + 1 > attempts) {
997     exceeded = 1;
998     start = stop - attempts + 1;
999   }
1000 
1001   // Construct new list of timestamps within the current time interval.
1002   char* list;
1003   {
1004     const size_t list_size = 25 * (2 + (stop - start + 1)) + 4;
1005     list = malloc(list_size);
1006     if (!list) {
1007       free(timestamps);
1008       goto oom;
1009     }
1010     snprintf(list, list_size, "%d %d", attempts, interval);
1011     char *prnt = strchr(list, '\000');
1012     for (int i = start; i <= stop; ++i) {
1013       prnt += snprintf(prnt, list_size-(prnt-list), " %u", timestamps[i]);
1014     }
1015     free(timestamps);
1016   }
1017 
1018   // Try to update RATE_LIMIT line.
1019   if (set_cfg_value(pamh, "RATE_LIMIT", list, buf) < 0) {
1020     free(list);
1021     return -1;
1022   }
1023   free(list);
1024 
1025   // Mark the state file as changed.
1026   *updated = 1;
1027 
1028   // If necessary, notify the user of the rate limiting that is in effect.
1029   if (exceeded) {
1030     log_message(LOG_ERR, pamh,
1031                 "Too many concurrent login attempts (\"%s\"). Please try again.", secret_filename);
1032     return -1;
1033   }
1034 
1035   return 0;
1036 }
1037 
get_first_pass(pam_handle_t * pamh)1038 static char *get_first_pass(pam_handle_t *pamh) {
1039   PAM_CONST void *password = NULL;
1040   if (pam_get_item(pamh, PAM_AUTHTOK, &password) == PAM_SUCCESS &&
1041       password) {
1042     return strdup((const char *)password);
1043   }
1044   return NULL;
1045 }
1046 
1047 // Show error message to the user.
1048 static void
conv_error(pam_handle_t * pamh,const char * text)1049 conv_error(pam_handle_t *pamh, const char* text) {
1050   PAM_CONST struct pam_message msg = {
1051     .msg_style = PAM_ERROR_MSG,
1052     .msg       = text,
1053   };
1054   PAM_CONST struct pam_message *msgs = &msg;
1055   struct pam_response *resp = NULL;
1056   const int retval = converse(pamh, 1, &msgs, &resp);
1057   if (retval != PAM_SUCCESS) {
1058     log_message(LOG_ERR, pamh, "Failed to inform user of error");
1059   }
1060   free(resp);
1061 }
1062 
request_pass(pam_handle_t * pamh,int echocode,PAM_CONST char * prompt)1063 static char *request_pass(pam_handle_t *pamh, int echocode,
1064                           PAM_CONST char *prompt) {
1065   // Query user for verification code
1066   PAM_CONST struct pam_message msg = { .msg_style = echocode,
1067                                    .msg       = prompt };
1068   PAM_CONST struct pam_message *msgs = &msg;
1069   struct pam_response *resp = NULL;
1070   int retval = converse(pamh, 1, &msgs, &resp);
1071   char *ret = NULL;
1072   if (retval != PAM_SUCCESS || resp == NULL || resp->resp == NULL ||
1073       *resp->resp == '\000') {
1074     log_message(LOG_ERR, pamh, "Did not receive verification code from user");
1075     if (retval == PAM_SUCCESS && resp && resp->resp) {
1076       ret = resp->resp;
1077     }
1078   } else {
1079     ret = resp->resp;
1080   }
1081 
1082   // Deallocate temporary storage
1083   if (resp) {
1084     if (!ret) {
1085       free(resp->resp);
1086     }
1087     free(resp);
1088   }
1089 
1090   return ret;
1091 }
1092 
1093 /* Checks for possible use of scratch codes. Returns -1 on error, 0 on success,
1094  * and 1, if no scratch code had been entered, and subsequent tests should be
1095  * applied.
1096  */
check_scratch_codes(pam_handle_t * pamh,const Params * params,const char * secret_filename,int * updated,char * buf,int code)1097 static int check_scratch_codes(pam_handle_t *pamh,
1098                                const Params *params,
1099                                const char *secret_filename,
1100                                int *updated, char *buf, int code) {
1101   // Skip the first line. It contains the shared secret.
1102   char *ptr = buf + strcspn(buf, "\n");
1103 
1104   // Check if this is one of the scratch codes
1105   char *endptr = NULL;
1106   for (;;) {
1107     // Skip newlines and blank lines
1108     while (*ptr == '\r' || *ptr == '\n') {
1109       ptr++;
1110     }
1111 
1112     // Skip any lines starting with double-quotes. They contain option fields
1113     if (*ptr == '"') {
1114       ptr += strcspn(ptr, "\n");
1115       continue;
1116     }
1117 
1118     // Try to interpret the line as a scratch code
1119     errno = 0;
1120     const int scratchcode = (int)strtoul(ptr, &endptr, 10);
1121 
1122     // Sanity check that we read a valid scratch code. Scratchcodes are all
1123     // numeric eight-digit codes. There must not be any other information on
1124     // that line.
1125     if (errno ||
1126         ptr == endptr ||
1127         (*endptr != '\r' && *endptr != '\n' && *endptr) ||
1128         scratchcode  <  10*1000*1000 ||
1129         scratchcode >= 100*1000*1000) {
1130       break;
1131     }
1132 
1133     // Check if the code matches
1134     if (scratchcode == code) {
1135       // Remove scratch code after using it
1136       while (*endptr == '\n' || *endptr == '\r') {
1137         ++endptr;
1138       }
1139       memmove(ptr, endptr, strlen(endptr) + 1);
1140       memset(strrchr(ptr, '\000'), 0, endptr - ptr + 1);
1141 
1142       // Mark the state file as changed
1143       *updated = 1;
1144 
1145       // Successfully removed scratch code. Allow user to log in.
1146       if(params->debug) {
1147         log_message(LOG_INFO, pamh, "debug: scratch code %d used and removed from \"%s\"", code, secret_filename);
1148       }
1149       return 0;
1150     }
1151     ptr = endptr;
1152   }
1153 
1154   // No scratch code has been used. Continue checking other types of codes.
1155   if(params->debug) {
1156     log_message(LOG_INFO, pamh, "debug: no scratch code used from \"%s\"", secret_filename);
1157   }
1158   return 1;
1159 }
1160 
window_size(pam_handle_t * pamh,const char * secret_filename,const char * buf)1161 static int window_size(pam_handle_t *pamh, const char *secret_filename,
1162                        const char *buf) {
1163   const char *value = get_cfg_value(pamh, "WINDOW_SIZE", buf);
1164   if (!value) {
1165     // Default window size is 3. This gives us one STEP_SIZE second
1166     // window before and after the current one.
1167     return 3;
1168   } else if (value == &oom) {
1169     // Out of memory. This is a fatal error.
1170     return 0;
1171   }
1172 
1173   char *endptr;
1174   errno = 0;
1175   const int window = (int)strtoul(value, &endptr, 10);
1176   if (errno || !*value || value == endptr ||
1177       (*endptr && *endptr != ' ' && *endptr != '\t' &&
1178        *endptr != '\n' && *endptr != '\r') ||
1179       window < 1 || window > 100) {
1180     free((void *)value);
1181     log_message(LOG_ERR, pamh, "Invalid WINDOW_SIZE option in \"%s\"",
1182                 secret_filename);
1183     return 0;
1184   }
1185   free((void *)value);
1186   return window;
1187 }
1188 
1189 /* If the DISALLOW_REUSE option has been set, record timestamps have been
1190  * used to log in successfully and disallow their reuse.
1191  *
1192  * Returns -1 on error, and 0 on success.
1193  */
invalidate_timebased_code(int tm,pam_handle_t * pamh,const char * secret_filename,int * updated,char ** buf)1194 static int invalidate_timebased_code(int tm, pam_handle_t *pamh,
1195                                      const char *secret_filename,
1196                                      int *updated, char **buf) {
1197   char *disallow = get_cfg_value(pamh, "DISALLOW_REUSE", *buf);
1198   if (!disallow) {
1199     // Reuse of tokens is not explicitly disallowed. Allow the login request
1200     // to proceed.
1201     return 0;
1202   } else if (disallow == &oom) {
1203     // Out of memory. This is a fatal error.
1204     return -1;
1205   }
1206 
1207   // Allow the user to customize the window size parameter.
1208   const int window = window_size(pamh, secret_filename, *buf);
1209   if (!window) {
1210     // The user configured a non-standard window size, but there was some
1211     // error with the value of this parameter.
1212     free((void *)disallow);
1213     return -1;
1214   }
1215 
1216   // The DISALLOW_REUSE option is followed by all known timestamps that are
1217   // currently unavailable for login.
1218   for (char *ptr = disallow; *ptr;) {
1219     // Skip white-space, if any
1220     ptr += strspn(ptr, " \t\r\n");
1221     if (!*ptr) {
1222       break;
1223     }
1224 
1225     // Parse timestamp value.
1226     char *endptr;
1227     errno = 0;
1228     const int blocked = (int)strtoul(ptr, &endptr, 10);
1229 
1230     // Treat syntactically invalid options as an error
1231     if (errno ||
1232         ptr == endptr ||
1233         (*endptr != ' ' && *endptr != '\t' &&
1234          *endptr != '\r' && *endptr != '\n' && *endptr)) {
1235       free((void *)disallow);
1236       return -1;
1237     }
1238 
1239     if (tm == blocked) {
1240       // The code is currently blocked from use. Disallow login.
1241       free((void *)disallow);
1242       const int step = step_size(pamh, secret_filename, *buf);
1243       if (!step) {
1244         return -1;
1245       }
1246       log_message(LOG_ERR, pamh,
1247                   "Trying to reuse a previously used time-based code. (\"%s\")"
1248                   "Retry again in %d seconds. "
1249                   "Warning! This might mean, you are currently subject to a "
1250                   "man-in-the-middle attack.", secret_filename, step);
1251       return -1;
1252     }
1253 
1254     // If the blocked code is outside of the possible window of timestamps,
1255     // remove it from the file.
1256     if (blocked - tm >= window || tm - blocked >= window) {
1257       endptr += strspn(endptr, " \t");
1258       memmove(ptr, endptr, strlen(endptr) + 1);
1259     } else {
1260       ptr = endptr;
1261     }
1262   }
1263 
1264   // Add the current timestamp to the list of disallowed timestamps.
1265   {
1266     const size_t resized_size = strlen(disallow) + 40;
1267     char *resized = realloc(disallow, resized_size);
1268     if (!resized) {
1269       free((void *)disallow);
1270       log_message(LOG_ERR, pamh,
1271                   "Failed to allocate memory when updating \"%s\"",
1272                   secret_filename);
1273       return -1;
1274     }
1275     disallow = resized;
1276     char* pos = strrchr(disallow, '\000');
1277     snprintf(pos, resized_size-(pos-disallow), " %d" + !*disallow, tm);
1278     if (set_cfg_value(pamh, "DISALLOW_REUSE", disallow, buf) < 0) {
1279       free((void *)disallow);
1280       return -1;
1281     }
1282     free((void *)disallow);
1283   }
1284 
1285   // Mark the state file as changed
1286   *updated = 1;
1287 
1288   // Allow access.
1289   return 0;
1290 }
1291 
1292 /* Given an input value, this function computes the hash code that forms the
1293  * expected authentication token.
1294  */
1295 #ifdef TESTING
1296 int compute_code(const uint8_t *secret, int secretLen, unsigned long value)
1297   __attribute__((visibility("default")));
1298 #else
1299 static
1300 #endif
compute_code(const uint8_t * secret,int secretLen,unsigned long value)1301 int compute_code(const uint8_t *secret, int secretLen, unsigned long value) {
1302   uint8_t val[8];
1303   for (int i = 8; i--; value >>= 8) {
1304     val[i] = value;
1305   }
1306   uint8_t hash[SHA1_DIGEST_LENGTH];
1307   hmac_sha1(secret, secretLen, val, 8, hash, SHA1_DIGEST_LENGTH);
1308   explicit_bzero(val, sizeof(val));
1309   const int offset = hash[SHA1_DIGEST_LENGTH - 1] & 0xF;
1310   unsigned int truncatedHash = 0;
1311   for (int i = 0; i < 4; ++i) {
1312     truncatedHash <<= 8;
1313     truncatedHash  |= hash[offset + i];
1314   }
1315   explicit_bzero(hash, sizeof(hash));
1316   truncatedHash &= 0x7FFFFFFF;
1317   truncatedHash %= 1000000;
1318   return truncatedHash;
1319 }
1320 
1321 /* If a user repeated attempts to log in with the same time skew, remember
1322  * this skew factor for future login attempts.
1323  */
check_time_skew(pam_handle_t * pamh,int * updated,char ** buf,int skew,int tm)1324 static int check_time_skew(pam_handle_t *pamh,
1325                            int *updated, char **buf, int skew, int tm) {
1326   int rc = -1;
1327 
1328   // Parse current RESETTING_TIME_SKEW line, if any.
1329   char *resetting = get_cfg_value(pamh, "RESETTING_TIME_SKEW", *buf);
1330   if (resetting == &oom) {
1331     // Out of memory. This is a fatal error.
1332     return -1;
1333   }
1334 
1335   // If the user can produce a sequence of three consecutive codes that fall
1336   // within a day of the current time. And if he can enter these codes in
1337   // quick succession, then we allow the time skew to be reset.
1338   // N.B. the number "3" was picked so that it would not trigger the rate
1339   // limiting limit if set up with default parameters.
1340   unsigned int tms[3];
1341   int skews[sizeof(tms)/sizeof(int)];
1342 
1343   int num_entries = 0;
1344   if (resetting) {
1345     char *ptr = resetting;
1346 
1347     // Read the three most recent pairs of time stamps and skew values into
1348     // our arrays.
1349     while (*ptr && *ptr != '\r' && *ptr != '\n') {
1350       char *endptr;
1351       errno = 0;
1352       const unsigned int i = (int)strtoul(ptr, &endptr, 10);
1353       if (errno || ptr == endptr || (*endptr != '+' && *endptr != '-')) {
1354         break;
1355       }
1356       ptr = endptr;
1357       int j = (int)strtoul(ptr + 1, &endptr, 10);
1358       if (errno ||
1359           ptr == endptr ||
1360           (*endptr != ' ' && *endptr != '\t' &&
1361            *endptr != '\r' && *endptr != '\n' && *endptr)) {
1362         break;
1363       }
1364       if (*ptr == '-') {
1365         j = -j;
1366       }
1367       if (num_entries == sizeof(tms)/sizeof(int)) {
1368         memmove(tms, tms+1, sizeof(tms)-sizeof(int));
1369         memmove(skews, skews+1, sizeof(skews)-sizeof(int));
1370       } else {
1371         ++num_entries;
1372       }
1373       tms[num_entries-1]   = i;
1374       skews[num_entries-1] = j;
1375       ptr = endptr;
1376     }
1377 
1378     // If the user entered an identical code, assume they are just getting
1379     // desperate. This doesn't actually provide us with any useful data,
1380     // though. Don't change any state and hope the user keeps trying a few
1381     // more times.
1382     if (num_entries &&
1383         tm + skew == tms[num_entries-1] + skews[num_entries-1]) {
1384       free((void *)resetting);
1385       return -1;
1386     }
1387   }
1388   free((void *)resetting);
1389 
1390   // Append new timestamp entry
1391   if (num_entries == sizeof(tms)/sizeof(int)) {
1392     memmove(tms, tms+1, sizeof(tms)-sizeof(int));
1393     memmove(skews, skews+1, sizeof(skews)-sizeof(int));
1394   } else {
1395     ++num_entries;
1396   }
1397   tms[num_entries-1]   = tm;
1398   skews[num_entries-1] = skew;
1399 
1400   // Check if we have the required amount of valid entries.
1401   if (num_entries == sizeof(tms)/sizeof(int)) {
1402     unsigned int last_tm = tms[0];
1403     int last_skew = skews[0];
1404     int avg_skew = last_skew;
1405     for (int i = 1; i < sizeof(tms)/sizeof(int); ++i) {
1406       // Check that we have a consecutive sequence of timestamps with no big
1407       // gaps in between. Also check that the time skew stays constant. Allow
1408       // a minor amount of fuzziness on all parameters.
1409       if (tms[i] <= last_tm || tms[i] > last_tm+2 ||
1410           last_skew - skew < -1 || last_skew - skew > 1) {
1411         goto keep_trying;
1412       }
1413       last_tm   = tms[i];
1414       last_skew = skews[i];
1415       avg_skew += last_skew;
1416     }
1417     avg_skew /= (int)(sizeof(tms)/sizeof(int));
1418 
1419     // The user entered the required number of valid codes in quick
1420     // succession. Establish a new valid time skew for all future login
1421     // attempts.
1422     char time_skew[40];
1423     snprintf(time_skew, sizeof time_skew, "%d", avg_skew);
1424     if (set_cfg_value(pamh, "TIME_SKEW", time_skew, buf) < 0) {
1425       return -1;
1426     }
1427     rc = 0;
1428   keep_trying:;
1429   }
1430 
1431   // Set the new RESETTING_TIME_SKEW line, while the user is still trying
1432   // to reset the time skew.
1433   {
1434     const size_t reset_size = 80 * (sizeof(tms)/sizeof(int));
1435     char reset[reset_size];
1436     *reset = '\000';
1437     if (rc) {
1438       for (int i = 0; i < num_entries; ++i) {
1439         char* pos = strrchr(reset, '\000');
1440         snprintf(pos, reset_size-(pos-reset), " %d%+d" + !*reset, tms[i], skews[i]);
1441       }
1442     }
1443     if (set_cfg_value(pamh, "RESETTING_TIME_SKEW", reset, buf) < 0) {
1444       return -1;
1445     }
1446   }
1447 
1448   // Mark the state file as changed
1449   *updated = 1;
1450 
1451   return rc;
1452 }
1453 
1454 /* Checks for time based verification code. Returns -1 on error, 0 on success,
1455  * and 1, if no time based code had been entered, and subsequent tests should
1456  * be applied.
1457  */
check_timebased_code(pam_handle_t * pamh,const char * secret_filename,int * updated,char ** buf,const uint8_t * secret,int secretLen,int code,Params * params)1458 static int check_timebased_code(pam_handle_t *pamh, const char*secret_filename,
1459                                 int *updated, char **buf, const uint8_t*secret,
1460                                 int secretLen, int code, Params *params) {
1461   if (!is_totp(*buf)) {
1462     // The secret file does not actually contain information for a time-based
1463     // code. Return to caller and see if any other authentication methods
1464     // apply.
1465     return 1;
1466   }
1467 
1468   if (code < 0 || code >= 1000000) {
1469     // All time based verification codes are no longer than six digits.
1470     return 1;
1471   }
1472 
1473   // Compute verification codes and compare them with user input
1474   const int tm = get_timestamp(pamh, secret_filename, (const char **)buf);
1475   if (!tm) {
1476     return -1;
1477   }
1478   const char *skew_str = get_cfg_value(pamh, "TIME_SKEW", *buf);
1479   if (skew_str == &oom) {
1480     // Out of memory. This is a fatal error
1481     return -1;
1482   }
1483 
1484   int skew = 0;
1485   if (skew_str) {
1486     skew = (int)strtol(skew_str, NULL, 10);
1487   }
1488   free((void *)skew_str);
1489 
1490   const int window = window_size(pamh, secret_filename, *buf);
1491   if (!window) {
1492     return -1;
1493   }
1494   for (int i = -((window-1)/2); i <= window/2; ++i) {
1495     const unsigned int hash = compute_code(secret, secretLen, tm + skew + i);
1496     if (hash == (unsigned int)code) {
1497       return invalidate_timebased_code(tm + skew + i, pamh, secret_filename,
1498                                        updated, buf);
1499     }
1500   }
1501 
1502   if (!params->noskewadj) {
1503     // The most common failure mode is for the clocks to be insufficiently
1504     // synchronized. We can detect this and store a skew value for future
1505     // use.
1506     skew = 1000000;
1507     for (int i = 0; i < 25*60; ++i) {
1508       unsigned int hash = compute_code(secret, secretLen, tm - i);
1509       if (hash == (unsigned int)code && skew == 1000000) {
1510         // Don't short-circuit out of the loop as the obvious difference in
1511         // computation time could be a signal that is valuable to an attacker.
1512         skew = -i;
1513       }
1514       hash = compute_code(secret, secretLen, tm + i);
1515       if (hash == (unsigned int)code && skew == 1000000) {
1516         skew = i;
1517       }
1518     }
1519     if (skew != 1000000) {
1520       if(params->debug) {
1521         log_message(LOG_INFO, pamh, "debug: time skew adjusted");
1522       }
1523       return check_time_skew(pamh, updated, buf, skew, tm);
1524     }
1525   }
1526 
1527   return 1;
1528 }
1529 
1530 /*
1531  * Add a 'config' variable that says we logged in from a particular place
1532  * at a particular time. Only remembers the last 10 logins, which
1533  * are replaced in LRU order.
1534  *
1535  * Returns 0 on success.
1536  */
1537 int
update_logindetails(pam_handle_t * pamh,const Params * params,char ** buf)1538 update_logindetails(pam_handle_t *pamh, const Params *params, char **buf) {
1539   const char *rhost = get_rhost(pamh, params);
1540   const time_t now = get_time();
1541   time_t oldest = now;    // Oldest entry seen so far.
1542   int oldest_index = -1;  // Index of oldest entry, due for replacement.
1543   int found = 0;          // Entry for this rhost found.
1544   char name[] = "LAST ";  // Config name template.
1545 
1546   if (rhost == NULL) {
1547     return -1;
1548   }
1549 
1550   for (int i = 0; i < 10; i++) {
1551     //
1552     // Get LAST<n> cfg value.
1553     //
1554     name[4] = i + '0';
1555     char *line = get_cfg_value(pamh, name, *buf);
1556     if (line == &oom) {
1557       /* Fatal! */
1558       return -1;
1559     }
1560 
1561     if (!line) {
1562       /* Make first empty line the oldest */
1563       if (oldest) {
1564         oldest_index = i;
1565         oldest = 0;
1566       }
1567       continue;
1568     }
1569 
1570     //
1571     // Parse value.
1572     //
1573 
1574     // Max len of ipv6 address is 8*4 digits plus 7 colons.
1575     // Plus trailing NUL is 40.
1576     // But RHOST can be FQDN, and by RFC1035 that's 255 characters as max.
1577     char host[256];
1578     unsigned long when = 0; // Timestamp of current entry.
1579     const int scanf_rc = sscanf(line, " %255[0-9a-zA-Z:.-] %lu ", host, &when);
1580     free(line);
1581 
1582     if (scanf_rc != 2) {
1583       log_message(LOG_ERR, pamh, "Malformed LAST%d line", i);
1584       continue;
1585     }
1586 
1587     if (!strcmp(host, rhost)) {
1588       found = 1;
1589       break;
1590     }
1591 
1592     if (when < oldest) {
1593       oldest_index = i;
1594       oldest = when;
1595     }
1596   }
1597 
1598   if (!found) {
1599     /* Loop completed all ten iterations */
1600     name[4] = oldest_index + '0';
1601   }
1602 
1603   /*
1604    * Max length in decimal digits of a 64 bit number is (64 log 2) + 1
1605    * Plus space and NUL termination, is 23.
1606    * Max len of hostname is 255.
1607    */
1608   char value[255+23+1];
1609   memset(value, 0, sizeof value);
1610 
1611   snprintf(value, sizeof value, "%s %lu", rhost, (unsigned long)now);
1612   if (set_cfg_value(pamh, name, value, buf) < 0) {
1613     log_message(LOG_WARNING, pamh, "Failed to set cfg value for login host");
1614   }
1615 
1616   return 0;
1617 }
1618 
1619 /*
1620  * Return non-zero if the last login from the same host as this one was
1621  * successfully authenticated within the grace period.
1622  */
1623 int
within_grace_period(pam_handle_t * pamh,const Params * params,const char * buf)1624 within_grace_period(pam_handle_t *pamh, const Params *params,
1625                     const char *buf) {
1626   const char *rhost = get_rhost(pamh, params);
1627   const time_t now = get_time();
1628   const time_t grace = params->grace_period;
1629   unsigned long when = 0;
1630   char match[128];
1631 
1632   if (rhost == NULL) {
1633     return 0;
1634   }
1635   snprintf(match, sizeof match, " %s %%lu ", rhost);
1636 
1637   for (int i = 0; i < 10; i++) {
1638     static char name[] = "LAST0";
1639     name[4] = i + '0';
1640     char* line = get_cfg_value(pamh, name, buf);
1641 
1642     if (line == &oom) {
1643       /* Fatal! */
1644       return 0;
1645     }
1646     if (!line) {
1647       continue;
1648     }
1649     if (sscanf(line, match, &when) == 1) {
1650       free(line);
1651       break;
1652     }
1653     free(line);
1654   }
1655 
1656   if (when == 0) {
1657     /* No match */
1658     return 0;
1659   }
1660 
1661   return (when + grace > now);
1662 }
1663 
1664 /* Checks for counter based verification code. Returns -1 on error, 0 on
1665  * success, and 1, if no counter based code had been entered, and subsequent
1666  * tests should be applied.
1667  */
check_counterbased_code(pam_handle_t * pamh,const char * secret_filename,int * updated,char ** buf,const uint8_t * secret,int secretLen,int code,long hotp_counter,int * must_advance_counter)1668 static int check_counterbased_code(pam_handle_t *pamh,
1669                                    const char*secret_filename, int *updated,
1670                                    char **buf, const uint8_t*secret,
1671                                    int secretLen, int code,
1672                                    long hotp_counter,
1673                                    int *must_advance_counter) {
1674   if (hotp_counter < 1) {
1675     // The secret file did not actually contain information for a counter-based
1676     // code. Return to caller and see if any other authentication methods
1677     // apply.
1678     return 1;
1679   }
1680 
1681   if (code < 0 || code >= 1000000) {
1682     // All counter based verification codes are no longer than six digits.
1683     return 1;
1684   }
1685 
1686   // Compute [window_size] verification codes and compare them with user input.
1687   // Future codes are allowed in case the user computed but did not use a code.
1688   const int window = window_size(pamh, secret_filename, *buf);
1689   if (!window) {
1690     return -1;
1691   }
1692   for (int i = 0; i < window; ++i) {
1693     const unsigned int hash = compute_code(secret, secretLen, hotp_counter + i);
1694     if (hash == (unsigned int)code) {
1695       char counter_str[40];
1696       snprintf(counter_str, sizeof counter_str, "%ld", hotp_counter + i + 1);
1697       if (set_cfg_value(pamh, "HOTP_COUNTER", counter_str, buf) < 0) {
1698         return -1;
1699       }
1700       *updated = 1;
1701       *must_advance_counter = 0;
1702       return 0;
1703     }
1704   }
1705 
1706   *must_advance_counter = 1;
1707   return 1;
1708 }
1709 
1710 // parse a user name.
1711 // input: user name
1712 // output: uid
1713 // return: 0 on success.
parse_user(pam_handle_t * pamh,const char * name,uid_t * uid)1714 static int parse_user(pam_handle_t *pamh, const char *name, uid_t *uid) {
1715   char *endptr;
1716   errno = 0;
1717   const long l = strtol(name, &endptr, 10);
1718   if (!errno && endptr != name && l >= 0 && l <= INT_MAX) {
1719     *uid = (uid_t)l;
1720     return 0;
1721   }
1722   const size_t len = getpwnam_buf_max_size();
1723   char *buf = malloc(len);
1724   if (!buf) {
1725     log_message(LOG_ERR, pamh, "Out of memory");
1726     return -1;
1727   }
1728   struct passwd pwbuf, *pw;
1729   if (getpwnam_r(name, &pwbuf, buf, len, &pw) || !pw) {
1730     free(buf);
1731     log_message(LOG_ERR, pamh, "Failed to look up user \"%s\"", name);
1732     return -1;
1733   }
1734   *uid = pw->pw_uid;
1735   free(buf);
1736   return 0;
1737 }
1738 
parse_args(pam_handle_t * pamh,int argc,const char ** argv,Params * params)1739 static int parse_args(pam_handle_t *pamh, int argc, const char **argv,
1740                       Params *params) {
1741   params->debug = 0;
1742   params->echocode = PAM_PROMPT_ECHO_OFF;
1743   for (int i = 0; i < argc; ++i) {
1744     if (!strncmp(argv[i], "secret=", 7)) {
1745       params->secret_filename_spec = argv[i] + 7;
1746     } else if (!strncmp(argv[i], "authtok_prompt=", 15)) {
1747       params->authtok_prompt = argv[i] + 15;
1748     } else if (!strncmp(argv[i], "user=", 5)) {
1749       uid_t uid;
1750       if (parse_user(pamh, argv[i] + 5, &uid) < 0) {
1751         return -1;
1752       }
1753       params->fixed_uid = 1;
1754       params->uid = uid;
1755     } else if (!strncmp(argv[i], "allowed_perm=", 13)) {
1756       char *remainder = NULL;
1757       const int perm = (int)strtol(argv[i] + 13, &remainder, 8);
1758       if (perm == 0 || strlen(remainder) != 0) {
1759         log_message(LOG_ERR, pamh,
1760                     "Invalid permissions in setting \"%s\"."
1761                     " allowed_perm setting must be a positive octal integer.",
1762                     argv[i]);
1763         return -1;
1764       }
1765       params->allowed_perm = perm;
1766     } else if (!strcmp(argv[i], "no_strict_owner")) {
1767       params->no_strict_owner = 1;
1768     } else if (!strcmp(argv[i], "debug")) {
1769       params->debug = 1;
1770     } else if (!strcmp(argv[i], "try_first_pass")) {
1771       params->pass_mode = TRY_FIRST_PASS;
1772     } else if (!strcmp(argv[i], "use_first_pass")) {
1773       params->pass_mode = USE_FIRST_PASS;
1774     } else if (!strcmp(argv[i], "forward_pass")) {
1775       params->forward_pass = 1;
1776     } else if (!strcmp(argv[i], "noskewadj")) {
1777       params->noskewadj = 1;
1778     } else if (!strcmp(argv[i], "no_increment_hotp")) {
1779       params->no_increment_hotp = 1;
1780     } else if (!strcmp(argv[i], "nullok")) {
1781       params->nullok = NULLOK;
1782     } else if (!strcmp(argv[i], "allow_readonly")) {
1783       params->allow_readonly = 1;
1784     } else if (!strcmp(argv[i], "echo-verification-code") ||
1785                !strcmp(argv[i], "echo_verification_code")) {
1786       params->echocode = PAM_PROMPT_ECHO_ON;
1787     } else if (!strncmp(argv[i], "grace_period=", 13)) {
1788       char *remainder = NULL;
1789       const time_t grace = (time_t)strtol(argv[i] + 13, &remainder, 10);
1790       if (grace < 0 || *remainder) {
1791         log_message(LOG_ERR, pamh,
1792                     "Invalid value in setting \"%s\"."
1793                     "grace_period must be a positive number of seconds.",
1794                     argv[i]);
1795         return -1;
1796       }
1797       params->grace_period = grace;
1798     } else {
1799       log_message(LOG_ERR, pamh, "Unrecognized option \"%s\"", argv[i]);
1800       return -1;
1801     }
1802   }
1803   return 0;
1804 }
1805 
google_authenticator(pam_handle_t * pamh,int argc,const char ** argv)1806 static int google_authenticator(pam_handle_t *pamh,
1807                                 int argc, const char **argv) {
1808   int        rc = PAM_AUTH_ERR;
1809   uid_t      uid = -1;
1810   int        old_uid = -1, old_gid = -1, fd = -1;
1811   char       *buf = NULL;
1812   struct stat orig_stat = { 0 };
1813   uint8_t    *secret = NULL;
1814   int        secretLen = 0;
1815 
1816   // Handle optional arguments that configure our PAM module
1817   Params params = { 0 };
1818   params.allowed_perm = 0600;
1819   if (parse_args(pamh, argc, argv, &params) < 0) {
1820     return rc;
1821   }
1822 
1823   const char *prompt = params.authtok_prompt
1824     ? params.authtok_prompt
1825     : (params.forward_pass ? PWCODE_PROMPT : CODE_PROMPT);
1826 
1827   // Read and process status file, then ask the user for the verification code.
1828   int early_updated = 0, updated = 0;
1829 
1830   const char* const username = get_user_name(pamh, &params);
1831   char* const secret_filename = get_secret_filename(pamh, &params,
1832                                                     username, &uid);
1833   int stopped_by_rate_limit = 0;
1834 
1835   // Drop privileges.
1836   {
1837     const char* drop_username = username;
1838 
1839     // If user doesn't exist, use 'nobody'.
1840     if (uid == -1) {
1841       drop_username = nobody;
1842       if (parse_user(pamh, drop_username, &uid)) {
1843         // If 'nobody' doesn't exist, bail. We need to drop privs to *someone*.
1844         goto out;
1845       }
1846     }
1847 
1848     if (drop_privileges(pamh, drop_username, uid, &old_uid, &old_gid)) {
1849       // Don't allow to continue without dropping privs.
1850       goto out;
1851     }
1852   }
1853 
1854   if (secret_filename) {
1855     fd = open_secret_file(pamh, secret_filename, &params, username, uid, &orig_stat);
1856     if (fd >= 0) {
1857       buf = read_file_contents(pamh, &params, secret_filename, &fd, orig_stat.st_size);
1858     }
1859 
1860     if (buf) {
1861       if (rate_limit(pamh, secret_filename, &early_updated, &buf) >= 0) {
1862         secret = get_shared_secret(pamh, &params, secret_filename, buf, &secretLen);
1863       } else {
1864         stopped_by_rate_limit=1;
1865       }
1866     }
1867   }
1868 
1869   const long hotp_counter = get_hotp_counter(pamh, buf);
1870 
1871   /*
1872    * Check to see if a successful login from the same host happened
1873    * within the grace period. If it did, then allow login without
1874    * an additional code.
1875    */
1876   if (buf && within_grace_period(pamh, &params, buf)) {
1877     rc = PAM_SUCCESS;
1878     log_message(LOG_INFO, pamh,
1879                 "within grace period: \"%s\"", username);
1880     goto out;
1881   }
1882 
1883   // Only if nullok and we do not have a code will we NOT ask for a code.
1884   // In all other cases (i.e "have code" and "no nullok and no code") we DO ask for a code.
1885   if (!stopped_by_rate_limit &&
1886         ( secret || params.nullok != SECRETNOTFOUND )
1887      ) {
1888 
1889     if (!secret) {
1890       log_message(LOG_WARNING , pamh, "No secret configured for user %s, asking for code anyway.", username);
1891     }
1892 
1893     int must_advance_counter = 0;
1894     char *pw = NULL, *saved_pw = NULL;
1895     for (int mode = 0; mode < 4; ++mode) {
1896       // In the case of TRY_FIRST_PASS, we don't actually know whether we
1897       // get the verification code from the system password or from prompting
1898       // the user. We need to attempt both.
1899       // This only works correctly, if all failed attempts leave the global
1900       // state unchanged.
1901       if (updated || pw) {
1902         // Oops. There is something wrong with the internal logic of our
1903         // code. This error should never trigger. The unittest checks for
1904         // this.
1905         if (pw) {
1906           explicit_bzero(pw, strlen(pw));
1907           free(pw);
1908           pw = NULL;
1909         }
1910         rc = PAM_AUTH_ERR;
1911         break;
1912       }
1913       switch (mode) {
1914       case 0: // Extract possible verification code
1915       case 1: // Extract possible scratch code
1916         if (params.pass_mode == USE_FIRST_PASS ||
1917             params.pass_mode == TRY_FIRST_PASS) {
1918           pw = get_first_pass(pamh);
1919         }
1920         break;
1921       default:
1922         if (mode != 2 && // Prompt for pw and possible verification code
1923             mode != 3) { // Prompt for pw and possible scratch code
1924           rc = PAM_AUTH_ERR;
1925           continue;
1926         }
1927         if (params.pass_mode == PROMPT ||
1928             params.pass_mode == TRY_FIRST_PASS) {
1929           if (!saved_pw) {
1930             // If forwarding the password to the next stacked PAM module,
1931             // we cannot tell the difference between an eight digit scratch
1932             // code or a two digit password immediately followed by a six
1933             // digit verification code. We have to loop and try both
1934             // options.
1935             saved_pw = request_pass(pamh, params.echocode, prompt);
1936           }
1937           if (saved_pw) {
1938             pw = strdup(saved_pw);
1939           }
1940         }
1941         break;
1942       }
1943       if (!pw) {
1944         continue;
1945       }
1946 
1947       // We are often dealing with a combined password and verification
1948       // code. Separate them now.
1949       const int pw_len = strlen(pw);
1950       const int expected_len = mode & 1 ? 8 : 6;
1951       char ch;
1952 
1953       // Full OpenSSH "bad password" is "\b\n\r\177INCORRECT", capped
1954       // to original password length.
1955       if (pw_len > 0 && pw[0] == '\b') {
1956         log_message(LOG_INFO, pamh,
1957                     "Dummy password supplied by PAM."
1958                     " Did OpenSSH 'PermitRootLogin <anything but yes>' or some"
1959                     " other config block this login?");
1960       }
1961 
1962       if (pw_len < expected_len ||
1963           // Verification are six digits starting with '0'..'9',
1964           // scratch codes are eight digits starting with '1'..'9'
1965           (ch = pw[pw_len - expected_len]) > '9' ||
1966           ch < (expected_len == 8 ? '1' : '0')) {
1967       invalid:
1968         explicit_bzero(pw, pw_len);
1969         free(pw);
1970         pw = NULL;
1971         continue;
1972       }
1973       char *endptr;
1974       errno = 0;
1975       const long l = strtol(pw + pw_len - expected_len, &endptr, 10);
1976       if (errno || l < 0 || *endptr) {
1977         goto invalid;
1978       }
1979       const int code = (int)l;
1980       memset(pw + pw_len - expected_len, 0, expected_len);
1981 
1982       if ((mode == 2 || mode == 3) && !params.forward_pass) {
1983         // We are explicitly configured so that we don't try to share
1984         // the password with any other stacked PAM module. We must
1985         // therefore verify that the user entered just the verification
1986         // code, but no password.
1987         if (*pw) {
1988           goto invalid;
1989         }
1990       }
1991 
1992       // Only if we actually have a secret will we try to verify the code
1993       // In all other cases will we just remain at PAM_AUTH_ERR
1994       if (secret) {
1995         // Check all possible types of verification codes.
1996         switch (check_scratch_codes(pamh, &params, secret_filename, &updated, buf, code)) {
1997         case 1:
1998           if (hotp_counter > 0) {
1999             switch (check_counterbased_code(pamh, secret_filename, &updated,
2000                                             &buf, secret, secretLen, code,
2001                                             hotp_counter,
2002                                             &must_advance_counter)) {
2003             case 0:
2004               rc = PAM_SUCCESS;
2005               break;
2006             case 1:
2007               goto invalid;
2008             default:
2009               break;
2010             }
2011           } else {
2012             switch (check_timebased_code(pamh, secret_filename, &updated, &buf,
2013                                          secret, secretLen, code, &params)) {
2014             case 0:
2015               rc = PAM_SUCCESS;
2016               break;
2017             case 1:
2018               goto invalid;
2019             default:
2020               break;
2021             }
2022           }
2023           break;
2024         case 0:
2025           rc = PAM_SUCCESS;
2026           break;
2027         default:
2028           break;
2029         }
2030 
2031         break;
2032       }
2033     }
2034 
2035     // Update the system password, if we were asked to forward
2036     // the system password. We already removed the verification
2037     // code from the end of the password.
2038     if (rc == PAM_SUCCESS && params.forward_pass) {
2039       if (!pw || pam_set_item(pamh, PAM_AUTHTOK, pw) != PAM_SUCCESS) {
2040         rc = PAM_AUTH_ERR;
2041       }
2042     }
2043 
2044     // Clear out password and deallocate memory
2045     if (pw) {
2046       explicit_bzero(pw,strlen(pw));
2047       free(pw);
2048     }
2049     if (saved_pw) {
2050       explicit_bzero(saved_pw, strlen(saved_pw));
2051       free(saved_pw);
2052     }
2053 
2054     // If an hotp login attempt has been made, the counter must always be
2055     // advanced by at least one, unless this has been disabled.
2056     if (!params.no_increment_hotp && must_advance_counter) {
2057       char counter_str[40];
2058       snprintf(counter_str, sizeof counter_str, "%ld", hotp_counter + 1);
2059       if (set_cfg_value(pamh, "HOTP_COUNTER", counter_str, &buf) < 0) {
2060         rc = PAM_AUTH_ERR;
2061       }
2062       updated = 1;
2063     }
2064 
2065     // Display a success or error message
2066     if (rc == PAM_SUCCESS) {
2067       log_message(LOG_INFO , pamh, "Accepted google_authenticator for %s", username);
2068       if (params.grace_period != 0) {
2069         if (update_logindetails(pamh, &params, &buf)) {
2070           log_message(LOG_ERR, pamh, "Failed to store grace_period timestamp in config");
2071         }
2072       }
2073     } else {
2074       log_message(LOG_ERR, pamh, "Invalid verification code for %s", username);
2075     }
2076   }
2077 
2078   // If the user has not created a state file with a shared secret, and if
2079   // the administrator set the "nullok" option, this PAM module completes
2080   // without saying success or failure, without ever prompting the user.
2081   // It's not a failure since "nullok" was specified, and it's not a success
2082   // because it must be distinguishable from "good credentials given" in
2083   // case the PAM config considers this module "sufficient".
2084   // (or more complex equivalents)
2085   if (params.nullok == SECRETNOTFOUND) {
2086     rc = PAM_IGNORE;
2087   }
2088 
2089   // Persist the new state.
2090   if (early_updated || updated) {
2091     int err;
2092     if ((err = write_file_contents(pamh, &params, secret_filename, &orig_stat, buf))) {
2093       // Inform user of error if the error is clearly a system error
2094       // and not an auth error.
2095       char s[1024];
2096       switch (err) {
2097       case EPERM:
2098       case ENOSPC:
2099       case EROFS:
2100       case EIO:
2101       case EDQUOT:
2102         snprintf(s, sizeof(s), "Error \"%s\" while writing config", strerror(err));
2103         conv_error(pamh, s);
2104       }
2105 
2106       // If allow_readonly parameter is defined than ignore write errors and
2107       // allow user to login.
2108       if (!params.allow_readonly) {
2109         // Could not persist new state. Deny access.
2110         rc = PAM_AUTH_ERR;
2111       }
2112     }
2113   }
2114 
2115 out:
2116   if (params.debug) {
2117     log_message(LOG_INFO, pamh,
2118                 "debug: end of google_authenticator for \"%s\". Result: %s",
2119                 username, pam_strerror(pamh, rc));
2120   }
2121   if (fd >= 0) {
2122     close(fd);
2123   }
2124   if (old_gid >= 0) {
2125     if (setgroup(old_gid) >= 0 && setgroup(old_gid) == old_gid) {
2126       old_gid = -1;
2127     }
2128   }
2129   if (old_uid >= 0) {
2130     if (setuser(old_uid) < 0 || setuser(old_uid) != old_uid) {
2131       log_message(LOG_EMERG, pamh, "We switched users from %d to %d, "
2132                   "but can't switch back", old_uid, uid);
2133     }
2134   }
2135   free(secret_filename);
2136 
2137   // Clean up
2138   if (buf) {
2139     explicit_bzero(buf, strlen(buf));
2140     free(buf);
2141   }
2142   if (secret) {
2143     explicit_bzero(secret, secretLen);
2144     free(secret);
2145   }
2146   return rc;
2147 }
2148 
2149 #ifndef UNUSED_ATTR
2150 # if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
2151 #  define UNUSED_ATTR __attribute__((__unused__))
2152 # else
2153 #  define UNUSED_ATTR
2154 # endif
2155 #endif
2156 
pam_sm_authenticate(pam_handle_t * pamh,int flags UNUSED_ATTR,int argc,const char ** argv)2157 PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED_ATTR,
2158                                    int argc, const char **argv) {
2159   return google_authenticator(pamh, argc, argv);
2160 }
2161 
2162 PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh UNUSED_ATTR,int flags UNUSED_ATTR,int argc UNUSED_ATTR,const char ** argv UNUSED_ATTR)2163 pam_sm_setcred (pam_handle_t *pamh UNUSED_ATTR,
2164                 int flags UNUSED_ATTR,
2165                 int argc UNUSED_ATTR,
2166                 const char **argv UNUSED_ATTR) {
2167   return PAM_SUCCESS;
2168 }
2169 
2170 #ifdef PAM_STATIC
2171 struct pam_module _pam_listfile_modstruct = {
2172   MODULE_NAME,
2173   pam_sm_authenticate,
2174   pam_sm_setcred,
2175   NULL,
2176   NULL,
2177   NULL,
2178   NULL
2179 };
2180 #endif
2181 /* ---- Emacs Variables ----
2182  * Local Variables:
2183  * c-basic-offset: 2
2184  * indent-tabs-mode: nil
2185  * End:
2186  */
2187