+/*
+Copyright (c) 2013 Eugene Crosser
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product documentation
+ would be appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+*/
+
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <unistd.h>
#include <errno.h>
#include <alloca.h>
+#include "base64.h"
#include "authobj.h"
#include "authfile.h"
* Template string may contain zero or one '~' and zero or one '?'.
* '~' at the beginning of the template string is substituted with
* the home directory of the userid. In any other position it is
- * substituted with the userid itself. '?' is substituted with the
- * tokenid. There is no way to make the resulting path contain '~'
- * or '?'. If there is more than one '~' or '?', or if the '~' is
- * at the beginning but userid does not resolve via getpwnam, or
- * the character to substitute is present but the argument is NULL,
- * NULL is returned. Otherwise, malloc()'ed area containg the path
- * string.
+ * substituted with the userid itself. There is no way to make the
+ * resulting path contain '~'. If there is more than one '~', or if
+ * the '~' is at the beginning but userid does not resolve via
+ * getpwnam, or '~' is present but the argument is NULL, path_size
+ * returns 0, and make_path returns 1.
*/
-static char *template = "~/.pam_cr/auth";
+static const char *template = "~/.pam_cr/auth";
-void authfile_template(char *str)
+void authfile_template(const char *str)
{
template = str;
}
-static int path_size(const char *tokenid, const char *userid)
+/*
+ I know using these two functions and alloca() in between it ugly, but
+ I like the alternatives even less. =ec
+*/
+
+static int path_size(const struct passwd *pw)
{
- const char *usub;
- char *p, *q;
- struct passwd *pw;
+ const char *p;
if ((p = strchr(template, '~')) != strrchr(template, '~')) return 0;
- if ((q = strchr(template, '?')) != strrchr(template, '?')) return 0;
- if (p && !userid) return 0;
- if (q && !tokenid) return 0;
- if (p == template) {
- pw = getpwnam(userid);
- if (!pw) return 0;
- usub = pw->pw_dir;
- } else {
- usub = userid;
- }
- return strlen(template) + p?strlen(usub):0 + q?strlen(tokenid):0 + 1;
+ if (p && !pw) return 0;
+ if (p == template) return strlen(template)+strlen(pw->pw_dir)+1;
+ else return strlen(template)+strlen(pw->pw_name)+1;
}
-static void
-make_path(char * const path, const char *tokenid, const char *userid)
+static int
+make_path(char * const path, const struct passwd *pw)
{
- const char *usub;
- char *p, *q;
- struct passwd *pw;
+ const char *p;
+ char *q;
path[0] = '\0';
- if (template[0] == '~') {
- pw = getpwnam(userid);
- if (!pw) return;
- usub = pw->pw_dir;
- } else {
- usub = userid;
- }
q = path;
for (p = template; *p; p++) switch (*p) {
case '~':
- strcpy(q, usub);
- while (*q) q++;
- break;
- case '?':
- strcpy(q, tokenid);
+ if (!pw) return 1;
+ if (p == template) strcpy(q, pw->pw_dir);
+ else strcpy(q, pw->pw_name);
while (*q) q++;
break;
default:
break;
}
*q = '\0';
+ return 0;
}
int parse(char * const buf, const int argc, const char *argv[const])
return i != argc;
}
-struct _auth_obj authfile(const char *tokenid,
- const char *userid, const char *password,
- void (*update_nonce)(char *nonce, const int nonsize),
- const unsigned char *secret, const int secsize,
- const unsigned char *payload, const int paylsize,
+struct _auth_obj authfile(const char *userid, const char *password,
+ void (*update_nonce)(char *nonce, const size_t nonsize),
+ const unsigned char *secret, const size_t secsize,
+ const unsigned char *payload, const size_t paylsize,
struct _auth_chunk (*fetch_key)(const unsigned char *chal,
- const int csize))
+ const size_t csize))
{
struct _auth_obj ret = {0};
+ const struct passwd *pw = NULL;
mode_t oldmask;
FILE *fp = NULL;
char *fn, *nfn;
int fnl;
+ struct stat st = {0};
char *buf = NULL;
struct {
- const char *tokenid;
const char *userid;
const char *nonce;
const char *hablob;
- } w = {"", NULL, NULL, NULL};
+ } w = {NULL, NULL, NULL};
unsigned char *ablob = NULL;
int blobsize = 0;
char *newnonce;
int nonsize;
struct _auth_obj ao;
- if ((fnl = path_size(tokenid, userid)) == 0) {
- ret.err = "authfile path impossible to build";
+ if (userid) pw = getpwnam(userid);
+ if ((fnl = path_size(pw)) == 0) {
+ ret.err = "authfile path_size failed";
return ret;
}
fn = alloca(fnl);
- make_path(fn, tokenid, userid);
+ if (make_path(fn, pw)) {
+ ret.err = "authfile make_path failed";
+ return ret;
+ }
nfn = alloca(fnl+32);
snprintf(nfn, fnl+32, "%s.%d.%ld", fn, (int)getpid(), (long)time(NULL));
fp = fopen(fn, "r");
if (fp) {
- struct stat st;
- int fd = fileno(fp);
-
- if (fstat(fd, &st)) st.st_size = 2047;
+ if (fstat(fileno(fp), &st)) st.st_size = 2047;
if (st.st_size > 2047) st.st_size = 2047;
buf = alloca(st.st_size + 1);
if (!fgets(buf, st.st_size + 1, fp)) {
if (ret.err) return ret;
if (w.hablob) {
- int hlen = strlen(w.hablob);
- if (hlen % 32 != 0) {
- ret.err = "error: auth string has wrong length";
- } else if (hlen !=
- strspn(w.hablob, "0123456789abcdefABCDEF")) {
- ret.err = "error: auth string not hexadecimal";
- } else {
- int i;
-
- blobsize = hlen/2;
- ablob = alloca(blobsize);
- for (i = 0; i < blobsize; i++)
- sscanf(&w.hablob[i*2], "%2hhx", &ablob[i]);
- }
+ blobsize = strlen(w.hablob)*3/4;
+ ablob = alloca(blobsize);
+ if (b64_decode(w.hablob, ablob, &blobsize))
+ ret.err = "error: undecodeable auth string";
}
if (ret.err) return ret;
oldmask = umask(077);
if ((fp = fopen(nfn, "w"))) {
- int i;
+ int bsize = ((ao.datasize-1)/3+1)*4+1;
+ char *b64 = alloca(bsize);
- if (fprintf(fp, "%s:%s:%s:", tokenid?tokenid:w.tokenid,
- userid?userid:w.userid, newnonce) < 0) {
- ret.err = strerror(errno);
- } else for (i = 0; i < ao.datasize; i++)
- if (fprintf(fp, "%02x", ao.data[i]) < 0) {
+ if (b64_encode(ao.data, ao.datasize, b64, &bsize)) {
+ ret.err = "error: could not encode auth string";
+ } else if (fprintf(fp, "%s:%s:%s\n",
+ userid?userid:w.userid, newnonce, b64) < 0) {
ret.err = strerror(errno);
}
- fprintf(fp, "\n");
+ if (st.st_uid || st.st_gid) {
+ if (fchown(fileno(fp), st.st_uid, st.st_gid)) {/*ign*/;}
+ }
if (fclose(fp) < 0) {
ret.err = strerror(errno);
}