OSDN Git Service

Merge remote-tracking branch 'toybox/master' into HEAD am: f353b240a5
[android-x86/external-toybox.git] / lib / password.c
index 34abf6e..eab2d66 100644 (file)
 /* password.c - password read/update helper functions.
  *
  * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
+ *
+ * TODO: cleanup
  */
 
 #include "toys.h"
-#include "xregcomp.h"
 #include <time.h>
 
+// generate appropriate random salt string for given encryption algorithm.
 int get_salt(char *salt, char *algo)
-{      
-  int i, len = 0, offset = 0;
-  char buf[12];
-
-  if (!strcmp(algo,"des")) len = 2;
-  else {
-    *salt++ = '$';
-    if (!strcmp(algo,"md5")) {
-      *salt++ = '1';
-      len = 8;
-    } else if (!strcmp(algo,"sha256")) {
-      *salt++ = '5';
-      len = 16;
-    } else if (!strcmp(algo,"sha512")) {
-      *salt++ = '6';
-      len = 16;
-    } else return -1;
-
-    *salt++ = '$';
-    offset = 3;
-  }    
-
-  // Read appropriate number of random bytes for salt
-  i = xopen("/dev/urandom", O_RDONLY);
-  xreadall(i, buf, ((len*6)+7)/8);
-  close(i);
-
-  // Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z
-  for (i=0; i<len; i++) {
-    int bitpos = i*6, bits = bitpos/8;
-
-    bits = ((buf[i]+(buf[i+1]<<8)) >> (bitpos&7)) & 0x3f;
-    bits += 46;
-    if (bits > 57) bits += 7;
-    if (bits > 90) bits += 6;
-
-    salt[i] = bits;
-  }
-  salt[i] = 0;
+{
+  struct {
+    char *type, id, len;
+  } al[] = {{"des", 0, 2}, {"md5", 1, 8}, {"sha256", 5, 16}, {"sha512", 6, 16}};
+  int i;
 
-  return offset;
-}
+  for (i = 0; i < ARRAY_LEN(al); i++) {
+    if (!strcmp(algo, al[i].type)) {
+      int len = al[i].len;
+      char *s = salt;
 
-static void handle(int signo)
-{
-  //Dummy.. so that read breaks on the signal, 
-  //instead of the applocation exit
+      if (al[i].id) s += sprintf(s, "$%c$", '0'+al[i].id);
+
+      // Read appropriate number of random bytes for salt
+      i = xopenro("/dev/urandom");
+      xreadall(i, libbuf, ((len*6)+7)/8);
+      close(i);
+
+      // Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z
+      for (i=0; i<len; i++) {
+        int bitpos = i*6, bits = bitpos/8;
+
+        bits = ((libbuf[i]+(libbuf[i+1]<<8)) >> (bitpos&7)) & 0x3f;
+        bits += 46;
+        if (bits > 57) bits += 7;
+        if (bits > 90) bits += 6;
+
+        s[i] = bits;
+      }
+      salt[len] = 0;
+
+      return s-salt;
+    }
+  }
+
+  return -1;
 }
 
-int read_password(char * buff, int buflen, char* mesg)
+// Prompt with mesg, read password into buf, return 0 for success 1 for fail
+int read_password(char *buf, int buflen, char *mesg)
 {
-  int i = 0;
-  struct termios termio, oldtermio;
+  struct termios oldtermio;
   struct sigaction sa, oldsa;
+  int i, ret = 1;
 
-  tcgetattr(0, &oldtermio);
-  tcflush(0, TCIFLUSH);
-  termio = oldtermio;
-
+  // NOP signal handler to return from the read
   memset(&sa, 0, sizeof(sa));
-  sa.sa_handler = handle;
+  sa.sa_handler = generic_signal;
   sigaction(SIGINT, &sa, &oldsa);
 
-  termio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
-  termio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP);
-  tcsetattr(0, TCSANOW, &termio);
-
-  fputs(mesg, stdout);
-  fflush(stdout);
-
-  while (1) {
-    int ret = read(0, &buff[i], 1);
-    if ( ret < 0 ) {
-      buff[0] = 0;
-      sigaction(SIGINT, &oldsa, NULL);
-      tcsetattr(0, TCSANOW, &oldtermio);
-      xputc('\n');
-      fflush(stdout);
-      return 1;
-    } else if (ret == 0 || buff[i] == '\n' || buff[i] == '\r' || buflen == i+1)
-    {
-      buff[i] = '\0';
+  tcflush(0, TCIFLUSH);
+  set_terminal(0, 1, &oldtermio);
+
+  xprintf("%s", mesg);
+
+  for (i=0; i < buflen-1; i++) {
+    if ((ret = read(0, buf+i, 1)) < 0 || (!ret && !i)) {
+      i = 0;
+      ret = 1;
+
       break;
-    }
-    i++;
+    } else if (!ret || buf[i] == '\n' || buf[i] == '\r') {
+      ret = 0;
+
+      break;
+    } else if (buf[i] == 8 || buf[i] == 127) i -= i ? 2 : 1;
   }
+
+  // Restore terminal/signal state, terminate string
   sigaction(SIGINT, &oldsa, NULL);
   tcsetattr(0, TCSANOW, &oldtermio);
-  puts("");
-  fflush(stdout);
-  return 0;
+  buf[i] = 0;
+  xputc('\n');
+
+  return ret;
 }
 
 static char *get_nextcolon(char *line, int cnt)
@@ -111,13 +97,14 @@ static char *get_nextcolon(char *line, int cnt)
 }
 
 /*update_password is used by multiple utilities to update /etc/passwd,
- * /etc/shadow, /etc/group and /etc/gshadow files, 
+ * /etc/shadow, /etc/group and /etc/gshadow files,
  * which are used as user, group databeses
- * entry can be 
+ * entry can be
  * 1. encrypted password, when updating user password.
  * 2. complete entry for user details, when creating new user
  * 3. group members comma',' separated list, when adding user to group
  * 4. complete entry for group details, when creating new group
+ * 5. entry = NULL, delete the named entry user/group
  */
 int update_password(char *filename, char* username, char* entry)
 {
@@ -128,7 +115,7 @@ int update_password(char *filename, char* username, char* entry)
   struct flock lock;
 
   shadow = strstr(filename, "shadow");
-  filenamesfx = xmsprintf("%s+", filename);
+  filenamesfx = xmprintf("%s+", filename);
   sfx = strchr(filenamesfx, '+');
 
   exfp = fopen(filename, "r+");
@@ -138,7 +125,7 @@ int update_password(char *filename, char* username, char* entry)
   }
 
   *sfx = '-';
-  ret = unlink(filenamesfx);
+  unlink(filenamesfx);
   ret = link(filename, filenamesfx);
   if (ret < 0) error_msg("can't create backup file");
 
@@ -162,12 +149,12 @@ int update_password(char *filename, char* username, char* entry)
   }
 
   ret = 0;
-  namesfx = xmsprintf("%s:",username);
+  namesfx = xmprintf("%s:",username);
   while ((line = get_line(fileno(exfp))) != NULL)
   {
     if (strncmp(line, namesfx, strlen(namesfx)))
       fprintf(newfp, "%s\n", line);
-    else {
+    else if (entry) {
       char *current_ptr = NULL;
 
       found = 1;
@@ -179,8 +166,10 @@ int update_password(char *filename, char* username, char* entry)
           current_ptr = get_nextcolon(current_ptr, 1);
           fprintf(newfp, "%s\n",current_ptr);
         } else fprintf(newfp, "%s\n",current_ptr);
-      } else if (!strcmp(toys.which->name, "groupadd") || 
-          !strcmp(toys.which->name, "addgroup")){
+      } else if (!strcmp(toys.which->name, "groupadd") ||
+          !strcmp(toys.which->name, "addgroup") ||
+          !strcmp(toys.which->name, "delgroup") ||
+          !strcmp(toys.which->name, "groupdel")){
         current_ptr = get_nextcolon(line, 3); //past gid/admin list
         *current_ptr = '\0';
         fprintf(newfp, "%s", line);
@@ -190,7 +179,7 @@ int update_password(char *filename, char* username, char* entry)
     free(line);
   }
   free(namesfx);
-  if (!found) fprintf(newfp, "%s\n", entry);
+  if (!found && entry) fprintf(newfp, "%s\n", entry);
   fcntl(fileno(exfp), F_SETLK, &lock);
   fclose(exfp);
 
@@ -209,29 +198,3 @@ free_storage:
   free(filenamesfx);
   return ret;
 }
-
-void is_valid_username(const char *name)                                                                                              
-{
-  regex_t rp;
-  regmatch_t rm[1]; 
-  int eval;
-  char *regex = "^[_.A-Za-z0-9][-_.A-Za-z0-9]*"; //User name REGEX
-
-  xregcomp(&rp, regex, REG_NEWLINE);
-
-  /* compare string against pattern --  remember that patterns 
-     are anchored to the beginning of the line */
-  eval = regexec(&rp, name, 1, rm, 0);
-  regfree(&rp);
-  if (!eval && !rm[0].rm_so) {
-    int len = strlen(name);
-    if ((rm[0].rm_eo == len) ||
-        (rm[0].rm_eo == len - 1 && name[len - 1] == '$')) {
-      if (len >= LOGIN_NAME_MAX) error_exit("name is too long");
-      else return;
-    }
-  }
-  error_exit("'%s', not valid %sname",name,
-      (((toys.which->name[3] == 'g') || 
-        (toys.which->name[0] == 'g'))? "group" : "user"));
-}