master xplshn/aruu / cmd / pseudo / mkpasswd.c
  1/* See LICENSE file for copyright and license details. */
  2#include "passwd.h"
  3#include "paths.h"
  4#include "util.h"
  5
  6#include <ctype.h>
  7#include <stdio.h>
  8#include <stdlib.h>
  9#include <string.h>
 10#include <unistd.h>
 11
 12static void
 13usage(void)
 14{
 15  eprintf("usage: %s [-P fd] [-m type] [-S salt] [password] [salt]\n", argv0);
 16}
 17
 18// ?man mkpasswd: encrypt the given password using salt
 19// ?man arguments: [password] [salt]
 20// ?man encrypt password using crypt(3) with random or provided salt
 21int
 22main(int argc, char *argv[])
 23{
 24  char *mflag, *sflag, *parg, *password, *cryptpass;
 25  char *prefix;
 26  char  salt[128];
 27  char  passbuf[1024];
 28  int   pfd, len;
 29
 30  mflag     = NULL;
 31  sflag     = NULL;
 32  parg      = NULL;
 33  password  = NULL;
 34  cryptpass = NULL;
 35  pfd       = -1;
 36  len       = 2;
 37  prefix    = NULL;
 38
 39  ARGBEGIN
 40  {
 41    case 'P':
 42      // ?man -P:fd: read password from file descriptor
 43      parg = EARGF(usage());
 44      pfd  = estrtonum(parg, 0, INT_MAX);
 45      break;
 46    case 'm':
 47      // ?man -m:type: encryption method (des, md5, sha256, sha512)
 48      mflag = EARGF(usage());
 49      break;
 50    case 'S':
 51      // ?man -S:salt: salt to use
 52      sflag = EARGF(usage());
 53      break;
 54    default:
 55      usage();
 56  }
 57  ARGEND
 58
 59  if (argc > 2)
 60    usage();
 61
 62  if (argc == 2) {
 63    if (sflag)
 64      eprintf("duplicate salt\n");
 65    sflag = argv[1];
 66  }
 67
 68  if (argc >= 1)
 69    password = argv[0];
 70
 71  if (!mflag)
 72    mflag = "des";
 73
 74  if (strcasecmp(mflag, "des") == 0) {
 75    len    = 2;
 76    prefix = NULL;
 77  } else if (strcasecmp(mflag, "md5") == 0) {
 78    len    = 8;
 79    prefix = "$1$";
 80  } else if (strcasecmp(mflag, "sha256") == 0) {
 81    len    = 16;
 82    prefix = "$5$";
 83  } else if (strcasecmp(mflag, "sha512") == 0) {
 84    len    = 16;
 85    prefix = "$6$";
 86  } else {
 87    eprintf("bad method: %s\n", mflag);
 88  }
 89
 90  if (sflag) {
 91    char *s = sflag;
 92    while (*s) {
 93      if (!isalnum((unsigned char)*s) && *s != '.' && *s != '/')
 94        eprintf("bad SALT (need [a-zA-Z0-9./])\n");
 95      s++;
 96    }
 97    if (prefix)
 98      snprintf(salt, sizeof(salt), "%s%s", prefix, sflag);
 99    else
100      estrlcpy(salt, sflag, sizeof(salt));
101  } else {
102    if (pw_gensalt_cipher(salt, sizeof(salt), prefix, len) < 0)
103      eprintf("pw_gensalt_cipher:");
104  }
105
106  if (pfd >= 0) {
107    if (dup2(pfd, 0) == -1)
108      eprintf("dup2:");
109    close(pfd);
110  }
111
112  if (!password) {
113    if (isatty(0)) {
114      char *p = getpass("Password: ");
115      if (!p)
116        eprintf("getpass failed\n");
117      estrlcpy(passbuf, p, sizeof(passbuf));
118      password = passbuf;
119    } else {
120      int bytes = read(0, passbuf, sizeof(passbuf) - 1);
121      if (bytes < 0)
122        eprintf("read stdin:");
123      while (bytes > 0 && (passbuf[bytes - 1] == '\n' || passbuf[bytes - 1] == '\r'))
124        bytes--;
125      passbuf[bytes] = '\0';
126      password       = passbuf;
127    }
128  }
129
130  cryptpass = crypt(password, salt);
131  if (!cryptpass)
132    eprintf("crypt:");
133  printf("%s\n", cryptpass);
134
135  if (fshut(stdout, "<stdout>"))
136    return 2;
137  return 0;
138}