Pastebin launched a little side project called HostCabi.net, check it out ;-)Don't like ads? PRO users don't see any ads ;-)
Guest

2stage.c

By: a guest on Jul 4th, 2012  |  syntax: C  |  size: 5.04 KB  |  hits: 2,107  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. /* 2stage v0
  2.  * ---
  3.  * Zachary Hamm
  4.  * zsh@imipolexg.org
  5.  *
  6.  * I often have to ssh into systems from untrusted public computers. The
  7.  * possibility of keyloggers makes me nervous (I'm the paranoid sort). I could
  8.  * use an ssh key on a usb drive or somesuch but that's often not an option,
  9.  * (plus, it's a nuisance to carry a precious usb drive around when I've got
  10.  * my passwords all stored up in my noggin). So I use password authentication.
  11.  * But those keyloggers torment me... keep me up at night...
  12.  *
  13.  * Googles two-stage auth  gives me the confidence to read my email at a public
  14.  * computer. I made this so I could have the same confidence when ssh'ing
  15.  * into my servers.
  16.  *
  17.  * Installation (requires libcurl and libreadline):
  18.  *   1. Edit the #defines below for yourself.
  19.  *   2. Build with cc 2stage.c -o 2stage -lcurl -lreadline
  20.  *   3. Move to /bin or some such.
  21.  *   4. Add /bin/2stage to /etc/shells
  22.  *   5. Edit /etc/passwd and set your shell to /bin/2stage
  23.  * And that's it. Try ssh'ing in.
  24.  *
  25.  *
  26.  * TODO: * Make it configurable by each user via a dotfile in the home dir.
  27.  *       * Option to remember trusted hosts for 30 days so you don't
  28.  *              have to do this over and over from your main boxen.
  29.  *       * Add logging of failed passcode attempts.
  30.  *       * Does this break X11 forwarding? Must test.
  31.  *       * Once all that is done, give it a proper autoconf and git host
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <fcntl.h>
  40. #include <errno.h>
  41.  
  42. #include <curl/curl.h>
  43. #include <readline/readline.h>
  44. #include <readline/history.h>
  45.  
  46. #define MSG "From: %s\r\nTo: %s\r\n\r\nYour two-stage passcode is %d\r\n"
  47.  
  48. /* Configuration happens here */
  49.  
  50. /* You */
  51. #define FROM "<zsh@imipolexg.org>"
  52.  
  53. /* Your SMS gateway or an email address if you don't want to use a phone */
  54. #define TO "<XXXXXXXX@messaging.sprintpcs.com>"
  55.  
  56. /* Set your preferred shell here */
  57. #define CONCH "/bin/bash"
  58.  
  59. int executeur(int argc, char **argv);
  60. unsigned int stupid_random(void);
  61. size_t mailbody(void *ptr, size_t size, size_t nitems, void *strm);
  62. int send_passcode(void);
  63.  
  64. static unsigned int passcode;
  65.  
  66. int executeur(int argcount, char **argvee)
  67. {
  68.         char **args = (char **)malloc(sizeof(char *) * (argcount + 1));
  69.         int i;
  70.  
  71.         args[0] = CONCH;
  72.         for(i = 1 ; i < argcount ; i++)
  73.         {
  74.                 args[i] = argvee[i];
  75.         }
  76.         args[argcount] = NULL;
  77.  
  78.         return execv(args[0], args);
  79. }
  80.  
  81. unsigned int stupid_random(void)
  82. {
  83.         int urandom_fd;
  84.         unsigned int randy = 0;
  85.  
  86.         urandom_fd = open("/dev/urandom", O_RDONLY);
  87.  
  88.         /* We want a number between 10^6 and 10^7 so that we get a 6 digit
  89.            number */
  90.         while (!(randy > (1000000 - 1) && randy < (10000000 - 1)))
  91.         {
  92.                 /* read 3 bytes intead of 4 to insure less hits over
  93.                    the threshold (so we get our random number faster) */
  94.                 read(urandom_fd, &randy, sizeof(unsigned int)-1);
  95.         }
  96.  
  97.         close(urandom_fd);
  98.  
  99.         return (unsigned int)randy;
  100. }
  101.  
  102.  
  103. /* Callback for CURLOPT_READFUNCTION */
  104. size_t mailbody(void *ptr, size_t size, size_t nitems, void *strm)
  105. {
  106.         static unsigned int dirty = 0;
  107.         char *s;
  108.         size_t len = 0;
  109.  
  110.         if(!dirty)
  111.         {
  112.                 /* 6 is the digit length of the ints from stupid_random()
  113.                    XXX: we assume malloc succeeds. this is sloppy. */
  114.                 s = (char *) malloc(strlen(MSG)+strlen(FROM)+strlen(TO)+6+1);
  115.                 passcode = stupid_random();
  116.                 sprintf(s, MSG, FROM, TO, passcode);
  117.                 len = strlen(s);
  118.                 memcpy(ptr, s, len);
  119.                 dirty = 1;
  120.                 free(s);
  121.  
  122.                 return len;
  123.         }
  124.  
  125.         return 0;
  126. }
  127.  
  128. int send_passcode(void)
  129. {
  130.         CURL *curl;
  131.         CURLcode res;
  132.         struct curl_slist *targets = NULL;
  133.        
  134.         curl = curl_easy_init();
  135.         if (!curl) {
  136.                 printf("Something bad happened to curl_easy_init()!");
  137.                 return -1;
  138.         }
  139.  
  140. /*      curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); */
  141.  
  142.         curl_easy_setopt(curl, CURLOPT_URL, "smtp://localhost");
  143.         targets = curl_slist_append(targets, TO);
  144.         curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, targets);
  145.         curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
  146.        
  147.         curl_easy_setopt(curl, CURLOPT_READFUNCTION, mailbody);
  148.        
  149.         res = curl_easy_perform(curl);
  150.         if(res != 0)
  151.         {
  152.                 printf("Something bad happened!\n");
  153.                 return -1;
  154.         }
  155.  
  156.         curl_slist_free_all(targets);
  157.         curl_easy_cleanup(curl);
  158.  
  159.         return 0;
  160. }
  161.  
  162. int main(int argc, char *argv[])
  163. {
  164.         char *input;
  165.  
  166.         printf("2stage! Sending the passcode to your phone.\n");
  167.         if(send_passcode() != 0)
  168.         {
  169.                 printf("Oh no! Badness! Try again or contact the admin...");
  170.                 return -1;
  171.         }      
  172.  
  173.         input = readline("Passcode sent! Have patience, then enter it: ");
  174.         if(strtol(input, NULL, 10) == passcode)
  175.         {
  176.                 printf("%s == %d!\nGood job!\n", input, passcode);
  177.                 free(input);
  178.         }
  179.         else
  180.         {
  181.                 free(input);   
  182.                 input = readline("No! Bad job! You get one more try: ");
  183.                 if(strtol(input, NULL, 10) == passcode)
  184.                 {
  185.                         printf("Good job!\n");
  186.                 }
  187.                 else
  188.                 {
  189.                         printf("Not this time, bub.\n");
  190.                         /* XXX: send textmsg about passcode failure. log it
  191.                            as well */
  192.                         return -1;
  193.                 }
  194.  
  195.                 free(input);
  196.         }
  197.  
  198.         if(executeur(argc, argv) == -1)
  199.         {
  200.                 perror("execv");
  201.                 return -1;
  202.         }
  203.  
  204.         return 0;
  205. }