ref: 8df8bdb45c315795a3a52f3fda0d8396a9eaac1a
dir: /chusr.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <libsec.h>
#include <authsrv.h>
#define KEYDB "/mnt/keys"
#define NETKEYDB "/mnt/netkeys"
#define KEYDBBUF (sizeof NETKEYDB) /* enough for any keydb prefix */
#define AUTHLOG "auth"
enum{
MAXNETCHAL = 100000, /* max securenet challenge */
Maxpath = 256,
};
enum
{
Nemail = 10,
Plan9 = 1,
Securenet = 2,
};
typedef struct
{
char *user;
char *postid;
char *name;
char *dept;
char *email[Nemail];
} Acctbio;
typedef struct {
char *keys;
char *msg;
char *who;
Biobuf *b;
} Fs;
Fs fs = { "/mnt/keys", "plan 9 key", "/adm/keys.who", 0 };
static uchar zeros[16];
void install(char*, char*, Authkey*, long);
int exists(char*, char*);
void private(void);
int setkey(char*, char*, Authkey*);
char* setdeskey(char*, char*, char*);
uchar* setaeskey(char*, char*, uchar*);
char* setsecret(char*, char*, char*);
void wrbio(char*, Acctbio*);
int writefile(char*, char*, int);
int deskeyfmt(Fmt*);
void
usage(void)
{
fprint(2, "usage: %s [-d dept] [-e email] [-i postid] [-s sponsor\'s email] -p pass user\n", argv0);
exits("usage");
}
void
main(int argc, char *argv[])
{
char *u, *pass;
long t;
Authkey key;
Acctbio a;
Fs *f;
fmtinstall('K', deskeyfmt);
ARGBEGIN{
case 'd':
a.dept = EARGF(usage());
break;
case 'i':
a.postid = EARGF(usage());
break;
case 'e':
a.email[0] = EARGF(usage());
break;
case 'p':
pass = EARGF(usage());
break;
/* sponsor's email */
case 's':
// a->email[1] = EARGF(usage());
break;
default:
usage();
}ARGEND
if(argc < 3)
usage();
u = *argv;
if(memchr(u, '\0', ANAMELEN) == 0)
sysfatal("bad user name");
private();
t = 0;
a.user = 0;
memset(&key, 0, sizeof(key));
f = &fs;
passtokey(&key, pass);
install(f->keys, u, &key, t);
if(setsecret(KEYDB, u, pass) == 0)
sysfatal("error writing Inferno/POP secret");
wrbio(f->who, &a);
print("user %s installed for Plan 9\n", u);
syslog(0, AUTHLOG, "user %s installed for plan 9", u);
exits(0);
}
void
install(char *db, char *u, Authkey *key, long t)
{
char buf[KEYDBBUF+ANAMELEN+20];
int fd;
if(!exists(db, u)){
snprint(buf, sizeof(buf), "%s/%s", db, u);
fd = create(buf, OREAD, 0777|DMDIR);
if(fd < 0)
sysfatal("can't create user %s: %r", u);
close(fd);
}
if(!setkey(db, u, key))
sysfatal("can't set key: %r");
if(t == -1)
return;
snprint(buf, sizeof(buf), "%s/%s/expire", db, u);
fd = open(buf, OWRITE);
if(fd < 0 || fprint(fd, "%ld", t) < 0)
sysfatal("can't write expiration time");
close(fd);
}
int
exists(char *db, char *u)
{
char buf[KEYDBBUF+ANAMELEN+6];
snprint(buf, sizeof(buf), "%s/%s/expire", db, u);
if(access(buf, 0) < 0)
return 0;
return 1;
}
/* these functions are from /sys/src/cmd/auth/lib/ */
int
deskeyfmt(Fmt *f)
{
uchar key[8];
char buf[32];
uchar *k;
int i;
k = va_arg(f->args, uchar*);
key[0] = 0;
for(i = 0; i < 7; i++){
key[i] |= k[i] >> i;
key[i] &= ~1;
key[i+1] = k[i] << (7 - i);
}
key[7] &= ~1;
sprint(buf, "%.3uo %.3uo %.3uo %.3uo %.3uo %.3uo %.3uo %.3uo",
key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]);
fmtstrcpy(f, buf);
return 0;
}
/* don't allow other processes to debug us and steal keys */
void
private(void)
{
int fd;
char buf[32];
static char pmsg[] = "Warning! %s can't protect itself from debugging: %r\n";
static char smsg[] = "Warning! %s can't turn off swapping: %r\n";
snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
fd = open(buf, OWRITE|OCEXEC);
if(fd < 0){
fprint(2, pmsg, argv0);
return;
}
if(fprint(fd, "private") < 0)
fprint(2, pmsg, argv0);
if(fprint(fd, "noswap") < 0)
fprint(2, smsg, argv0);
close(fd);
}
int
setkey(char *db, char *user, Authkey *key)
{
int ret;
ret = setdeskey(db, user, key->des) != nil;
if(tsmemcmp(key->aes, zeros, AESKEYLEN) != 0)
ret |= setaeskey(db, user, key->aes) != nil;
return ret;
}
char*
setdeskey(char *db, char *user, char *key)
{
char filename[Maxpath];
snprint(filename, sizeof filename, "%s/%s/key", db, user);
if(writefile(filename, key, DESKEYLEN) != DESKEYLEN)
return nil;
return key;
}
uchar*
setaeskey(char *db, char *user, uchar *key)
{
char filename[Maxpath];
snprint(filename, sizeof filename, "%s/%s/aeskey", db, user);
if(writefile(filename, (char*)key, AESKEYLEN) != AESKEYLEN)
return nil;
return key;
}
char*
setsecret(char *db, char *user, char *secret)
{
char filename[Maxpath];
snprint(filename, sizeof filename, "%s/%s/secret", db, user);
if(writefile(filename, secret, strlen(secret)) != strlen(secret))
return nil;
return secret;
}
void
wrbio(char *file, Acctbio *a)
{
char buf[1024];
int i, fd, n;
fd = open(file, OWRITE);
if(fd < 0){
fd = create(file, OWRITE, 0660);
if(fd < 0)
sysfatal("can't create %s", file);
}
if(seek(fd, 0, 2) < 0)
sysfatal("can't seek %s", file);
if(a->postid == 0)
a->postid = "";
if(a->name == 0)
a->name = "";
if(a->dept == 0)
a->dept = "";
if(a->email[0] == 0)
a->email[0] = strdup(a->user);
n = 0;
n += snprint(buf+n, sizeof(buf)-n, "%s|%s|%s|%s",
a->user, a->postid, a->name, a->dept);
for(i = 0; i < Nemail; i++){
if(a->email[i] == 0)
break;
n += snprint(buf+n, sizeof(buf)-n, "|%s", a->email[i]);
}
n += snprint(buf+n, sizeof(buf)-n, "\n");
write(fd, buf, n);
close(fd);
}
int
writefile(char *file, char *buf, int n)
{
int fd;
fd = open(file, OWRITE);
if(fd < 0)
return -1;
n = write(fd, buf, n);
close(fd);
return n;
}