mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-18 06:22:27 +02:00
349 lines
7.4 KiB
C
349 lines
7.4 KiB
C
|
/* Add passphrases to the tpasswd file. Use the last entry in the config
|
||
|
file by default or a particular one specified by index. */
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include "config.h"
|
||
|
#include "t_pwd.h"
|
||
|
#include "t_read.h"
|
||
|
#include "t_sha.h"
|
||
|
#include "t_defines.h"
|
||
|
|
||
|
char *Progname;
|
||
|
char Usage[] = "usage: %s [-n configindex] [-p passfile] user\n";
|
||
|
#define USAGE() fprintf(stderr, Usage, Progname)
|
||
|
|
||
|
void doit(char *);
|
||
|
|
||
|
int Configindex = -1;
|
||
|
char *Passfile = DEFAULT_PASSWD;
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
int c;
|
||
|
|
||
|
Progname = *argv;
|
||
|
|
||
|
/* Parse option arguments. */
|
||
|
|
||
|
while ((c = getopt(argc, argv, "n:p:")) != EOF) {
|
||
|
switch (c) {
|
||
|
|
||
|
case 'n':
|
||
|
Configindex = atoi(optarg);
|
||
|
break;
|
||
|
|
||
|
case 'p':
|
||
|
Passfile = optarg;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
USAGE();
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
argc -= optind;
|
||
|
argv += optind;
|
||
|
|
||
|
if (argc != 1) {
|
||
|
USAGE();
|
||
|
exit(1);
|
||
|
}
|
||
|
doit(argv[0]);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void doit(char *name)
|
||
|
{
|
||
|
char passphrase[128], passphrase1[128];
|
||
|
FILE *f;
|
||
|
struct t_conf *tc;
|
||
|
struct t_confent *tcent;
|
||
|
struct t_pw eps_passwd;
|
||
|
|
||
|
/* Get the config entry. */
|
||
|
|
||
|
if (Configindex <= 0) {
|
||
|
Configindex = t_getprecount();
|
||
|
}
|
||
|
tcent = gettcid(Configindex);
|
||
|
if (tcent == NULL) {
|
||
|
fprintf(stderr, "Invalid configuration file entry.\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
/* Ask for the passphrase twice. */
|
||
|
|
||
|
printf("Setting passphrase for %s\n", name);
|
||
|
|
||
|
if (t_getpass(passphrase, sizeof(passphrase), "Enter passphrase: ") < 0) {
|
||
|
exit(1);
|
||
|
}
|
||
|
if (t_getpass(passphrase1, sizeof(passphrase1), "Verify: ") < 0) {
|
||
|
exit(1);
|
||
|
}
|
||
|
if (strcmp(passphrase, passphrase1) != 0) {
|
||
|
fprintf(stderr, "mismatch\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
/* Create the passphrase verifier. */
|
||
|
|
||
|
t_makepwent(&eps_passwd, name, passphrase, NULL, tcent);
|
||
|
|
||
|
/* Don't need these anymore. */
|
||
|
|
||
|
memset(passphrase, 0, sizeof(passphrase));
|
||
|
memset(passphrase1, 0, sizeof(passphrase1));
|
||
|
|
||
|
/* See if the passphrase file is there; create it if not. */
|
||
|
|
||
|
if ((f = fopen(Passfile, "r+")) == NULL) {
|
||
|
creat(Passfile, 0400);
|
||
|
} else {
|
||
|
fclose(f);
|
||
|
}
|
||
|
|
||
|
/* Change the passphrase. */
|
||
|
|
||
|
if (t_changepw(Passfile, &eps_passwd.pebuf) < 0) {
|
||
|
fprintf(stderr, "Error changing passphrase\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* TODO: Implement a more general method to handle delete/change */
|
||
|
|
||
|
_TYPE( int )
|
||
|
t_changepw(pwname, diff)
|
||
|
const char * pwname;
|
||
|
const struct t_pwent * diff;
|
||
|
{
|
||
|
char * bakfile;
|
||
|
char * bakfile2;
|
||
|
struct stat st;
|
||
|
FILE * passfp;
|
||
|
FILE * bakfp;
|
||
|
|
||
|
if(pwname == NULL)
|
||
|
pwname = DEFAULT_PASSWD;
|
||
|
|
||
|
if((passfp = fopen(pwname, "rb")) == NULL || fstat(fileno(passfp), &st) < 0)
|
||
|
return -1;
|
||
|
|
||
|
if((bakfile = malloc(strlen(pwname) + 5)) == NULL) {
|
||
|
fclose(passfp);
|
||
|
return -1;
|
||
|
}
|
||
|
else if((bakfile2 = malloc(strlen(pwname) + 5)) == NULL) {
|
||
|
fclose(passfp);
|
||
|
free(bakfile);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
sprintf(bakfile, "%s.bak", pwname);
|
||
|
sprintf(bakfile2, "%s.sav", pwname);
|
||
|
|
||
|
if((bakfp = fopen(bakfile2, "wb")) == NULL &&
|
||
|
(unlink(bakfile2) < 0 || (bakfp = fopen(bakfile2, "wb")) == NULL)) {
|
||
|
fclose(passfp);
|
||
|
fclose(bakfp);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
#ifdef NO_FCHMOD
|
||
|
chmod(bakfile2, st.st_mode & 0777);
|
||
|
#else
|
||
|
fchmod(fileno(bakfp), st.st_mode & 0777);
|
||
|
#endif
|
||
|
|
||
|
t_pwcopy(bakfp, passfp, diff);
|
||
|
|
||
|
fclose(bakfp);
|
||
|
fclose(passfp);
|
||
|
|
||
|
#ifdef USE_RENAME
|
||
|
unlink(bakfile);
|
||
|
if(rename(pwname, bakfile) < 0)
|
||
|
return -1;
|
||
|
if(rename(bakfile2, pwname) < 0)
|
||
|
return -1;
|
||
|
#else
|
||
|
unlink(bakfile);
|
||
|
link(pwname, bakfile);
|
||
|
unlink(pwname);
|
||
|
link(bakfile2, pwname);
|
||
|
unlink(bakfile2);
|
||
|
#endif
|
||
|
free(bakfile);
|
||
|
free(bakfile2);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
_TYPE( struct t_pwent * )
|
||
|
t_makepwent(tpw, user, pass, salt, confent)
|
||
|
struct t_pw * tpw;
|
||
|
const char * user;
|
||
|
const char * pass;
|
||
|
const struct t_num * salt;
|
||
|
const struct t_confent * confent;
|
||
|
{
|
||
|
BigInteger x, v, n, g;
|
||
|
unsigned char dig[SHA_DIGESTSIZE];
|
||
|
SHA1_CTX ctxt;
|
||
|
|
||
|
tpw->pebuf.name = tpw->userbuf;
|
||
|
tpw->pebuf.password.data = tpw->pwbuf;
|
||
|
tpw->pebuf.salt.data = tpw->saltbuf;
|
||
|
|
||
|
strncpy(tpw->pebuf.name, user, MAXUSERLEN);
|
||
|
tpw->pebuf.index = confent->index;
|
||
|
|
||
|
if(salt) {
|
||
|
tpw->pebuf.salt.len = salt->len;
|
||
|
memcpy(tpw->pebuf.salt.data, salt->data, salt->len);
|
||
|
}
|
||
|
else {
|
||
|
memset(dig, 0, SALTLEN); /* salt is 80 bits */
|
||
|
tpw->pebuf.salt.len = SALTLEN;
|
||
|
do {
|
||
|
t_random(tpw->pebuf.salt.data, SALTLEN);
|
||
|
} while(memcmp(tpw->pebuf.salt.data, dig, SALTLEN) == 0);
|
||
|
if(tpw->pebuf.salt.data[0] == 0)
|
||
|
tpw->pebuf.salt.data[0] = 0xff;
|
||
|
}
|
||
|
|
||
|
n = BigIntegerFromBytes(confent->modulus.data, confent->modulus.len);
|
||
|
g = BigIntegerFromBytes(confent->generator.data, confent->generator.len);
|
||
|
v = BigIntegerFromInt(0);
|
||
|
|
||
|
SHA1Init(&ctxt);
|
||
|
SHA1Update(&ctxt, user, strlen(user));
|
||
|
SHA1Update(&ctxt, ":", 1);
|
||
|
SHA1Update(&ctxt, pass, strlen(pass));
|
||
|
SHA1Final(dig, &ctxt);
|
||
|
|
||
|
SHA1Init(&ctxt);
|
||
|
SHA1Update(&ctxt, tpw->pebuf.salt.data, tpw->pebuf.salt.len);
|
||
|
SHA1Update(&ctxt, dig, sizeof(dig));
|
||
|
SHA1Final(dig, &ctxt);
|
||
|
|
||
|
/* x = H(s, H(u, ':', p)) */
|
||
|
x = BigIntegerFromBytes(dig, sizeof(dig));
|
||
|
|
||
|
BigIntegerModExp(v, g, x, n);
|
||
|
tpw->pebuf.password.len = BigIntegerToBytes(v, tpw->pebuf.password.data);
|
||
|
|
||
|
BigIntegerFree(v);
|
||
|
BigIntegerFree(x);
|
||
|
BigIntegerFree(g);
|
||
|
BigIntegerFree(n);
|
||
|
|
||
|
return &tpw->pebuf;
|
||
|
}
|
||
|
|
||
|
int
|
||
|
t_pwcopy(pwdest, pwsrc, diff)
|
||
|
FILE * pwdest;
|
||
|
FILE * pwsrc;
|
||
|
struct t_pwent * diff;
|
||
|
{
|
||
|
struct t_pw * src;
|
||
|
struct t_pwent * ent;
|
||
|
|
||
|
if((src = t_openpw(pwsrc)) == NULL)
|
||
|
return -1;
|
||
|
|
||
|
while((ent = t_getpwent(src)) != NULL)
|
||
|
if(diff && strcmp(diff->name, ent->name) == 0) {
|
||
|
t_putpwent(diff, pwdest);
|
||
|
diff = NULL;
|
||
|
}
|
||
|
else
|
||
|
t_putpwent(ent, pwdest);
|
||
|
|
||
|
if(diff)
|
||
|
t_putpwent(diff, pwdest);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
_TYPE( struct t_pwent * )
|
||
|
t_getpwent(tpw)
|
||
|
struct t_pw * tpw;
|
||
|
{
|
||
|
char indexbuf[16];
|
||
|
char passbuf[MAXB64PARAMLEN];
|
||
|
char saltstr[MAXB64SALTLEN];
|
||
|
|
||
|
#ifdef ENABLE_YP
|
||
|
struct t_passwd * nisent;
|
||
|
/* FIXME: should tell caller to get conf entry from NIS also */
|
||
|
|
||
|
if(tpw->state == IN_NIS) {
|
||
|
nisent = _yp_gettpent();
|
||
|
if(nisent != NULL) {
|
||
|
savepwent(tpw, &nisent->tp);
|
||
|
return &tpw->pebuf;
|
||
|
}
|
||
|
tpw->state = FILE_NIS;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
while(1) {
|
||
|
if(t_nextfield(tpw->instream, tpw->userbuf, MAXUSERLEN) > 0) {
|
||
|
#ifdef ENABLE_YP
|
||
|
if(tpw->state == FILE_NIS && *tpw->userbuf == '+') {
|
||
|
t_nextline(tpw->instream);
|
||
|
if(strlen(tpw->userbuf) > 1) { /* +name:... */
|
||
|
nisent = _yp_gettpnam(tpw->userbuf + 1);
|
||
|
if(nisent != NULL) {
|
||
|
savepwent(tpw, nisent);
|
||
|
return &tpw->pebuf;
|
||
|
}
|
||
|
}
|
||
|
else { /* +:... */
|
||
|
tpw->state = IN_NIS;
|
||
|
_yp_settpent();
|
||
|
return t_getpwent(tpw);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
if(t_nextfield(tpw->instream, passbuf, MAXB64PARAMLEN) > 0 &&
|
||
|
(tpw->pebuf.password.len = t_fromb64(tpw->pwbuf, passbuf)) > 0 &&
|
||
|
t_nextfield(tpw->instream, saltstr, MAXB64SALTLEN) > 0 &&
|
||
|
(tpw->pebuf.salt.len = t_fromb64(tpw->saltbuf, saltstr)) > 0 &&
|
||
|
t_nextfield(tpw->instream, indexbuf, 16) > 0 &&
|
||
|
(tpw->pebuf.index = atoi(indexbuf)) > 0) {
|
||
|
tpw->pebuf.name = tpw->userbuf;
|
||
|
tpw->pebuf.password.data = tpw->pwbuf;
|
||
|
tpw->pebuf.salt.data = tpw->saltbuf;
|
||
|
t_nextline(tpw->instream);
|
||
|
return &tpw->pebuf;
|
||
|
}
|
||
|
}
|
||
|
if(t_nextline(tpw->instream) < 0)
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_TYPE( void )
|
||
|
t_putpwent(ent, fp)
|
||
|
const struct t_pwent * ent;
|
||
|
FILE * fp;
|
||
|
{
|
||
|
char strbuf[MAXB64PARAMLEN];
|
||
|
char saltbuf[MAXB64SALTLEN];
|
||
|
|
||
|
fprintf(fp, "%s:%s:%s:%d\n", ent->name,
|
||
|
t_tob64(strbuf, ent->password.data, ent->password.len),
|
||
|
t_tob64(saltbuf, ent->salt.data, ent->salt.len), ent->index);
|
||
|
}
|
||
|
|