X-Git-Url: http://www.average.org/gitweb/?p=pam_pcsc_cr.git;a=blobdiff_plain;f=authfile.c;h=c43b2d655b0a6f2ee1d7640b648b0cc0cf9f35c7;hp=9b1313c85ce63e6aa1964043d703bfbcd7c8fdcb;hb=dc50dc3cbff0a815c899828c991e17f85458631c;hpb=33ff3039428415fa441fe9e2b21a854cfcb75151;ds=sidebyside diff --git a/authfile.c b/authfile.c index 9b1313c..c43b2d6 100644 --- a/authfile.c +++ b/authfile.c @@ -1,9 +1,33 @@ +/* +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 #include #include +#include #include #include #include @@ -26,34 +50,49 @@ * string. */ -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 char *make_path(const char *tokenid, const char *userid) +static int path_size(const char *tokenid, const char *userid) { const char *usub; - char *path; - char *p, *q; + const char *p, *q; struct passwd *pw; - if ((p = strchr(template, '~')) != strrchr(template, '~')) return NULL; - if ((q = strchr(template, '?')) != strrchr(template, '?')) return NULL; - if (p && !userid) return NULL; - if (q && !tokenid) return NULL; + 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 NULL; + if (!pw) return 0; + usub = pw->pw_dir; + } else { + usub = userid; + } + return strlen(template)+(p?strlen(usub):0)+(q?strlen(tokenid):0)+1; +} + +static void +make_path(char * const path, const char *tokenid, const char *userid) +{ + const char *usub; + const char *p; + char *q; + struct passwd *pw; + + path[0] = '\0'; + if (template[0] == '~') { + pw = getpwnam(userid); + if (!pw) return; usub = pw->pw_dir; } else { usub = userid; } - path = malloc(strlen(template) + p?strlen(usub):0 + - q?strlen(tokenid):0 + 1); - if (!path) return NULL; q = path; for (p = template; *p; p++) switch (*p) { case '~': @@ -69,7 +108,19 @@ static char *make_path(const char *tokenid, const char *userid) break; } *q = '\0'; - return path; +} + +int parse(char * const buf, const int argc, const char *argv[const]) +{ + char *p, *q; + int i; + + for (i = 0, p = buf; *p; p = q+1, i++) { + for (q = p; *q && *q != ':' && *q != '\r' && *q != '\n'; q++) ; + *q = '\0'; + if (*p && i < argc) argv[i] = p; + } + return i != argc; } struct _auth_obj authfile(const char *tokenid, @@ -81,52 +132,53 @@ struct _auth_obj authfile(const char *tokenid, const int csize)) { struct _auth_obj ret = {0}; + mode_t oldmask; FILE *fp = NULL; - char *fn; + char *fn, *nfn; + int fnl; + struct stat st = {0}; char *buf = NULL; - const char *wtokenid = NULL, *wuserid = NULL, *wnonce = NULL; - const char *hablob = NULL; + struct { + const char *tokenid; + const char *userid; + const char *nonce; + const char *hablob; + } w = {"", NULL, NULL, NULL}; unsigned char *ablob = NULL; int blobsize = 0; char *newnonce; int nonsize; struct _auth_obj ao; - if ((fn = make_path(tokenid, userid)) == NULL) { + if ((fnl = path_size(tokenid, userid)) == 0) { ret.err = "authfile path impossible to build"; return ret; } + fn = alloca(fnl); + make_path(fn, tokenid, userid); + nfn = alloca(fnl+32); + snprintf(nfn, fnl+32, "%s.%d.%ld", fn, (int)getpid(), (long)time(NULL)); fp = fopen(fn, "r"); - free(fn); 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)) { - char *p; - - p = &buf[strlen(buf) - 1]; - while (*p == '\n' || *p == '\r') *p-- = '\0'; - wtokenid = strtok(buf, ":"); - wuserid = strtok(NULL, ":"); - wnonce = strtok(NULL, ":"); - hablob = strtok(NULL, ":"); - } else { + if (!fgets(buf, st.st_size + 1, fp)) { ret.err = strerror(errno); + } else if (parse(buf, sizeof(w)/sizeof(char*), + (const char ** const)&w)){ + ret.err = "error: unparseable auth file"; } fclose(fp); } if (ret.err) return ret; - if (hablob) { - int hlen = strlen(hablob); + if (w.hablob) { + int hlen = strlen(w.hablob); if (hlen % 32 != 0) { ret.err = "error: auth string has wrong length"; } else if (hlen != - strspn(hablob, "0123456789abcdefABCDEF")) { + strspn(w.hablob, "0123456789abcdefABCDEF")) { ret.err = "error: auth string not hexadecimal"; } else { int i; @@ -134,20 +186,20 @@ struct _auth_obj authfile(const char *tokenid, blobsize = hlen/2; ablob = alloca(blobsize); for (i = 0; i < blobsize; i++) - sscanf(&hablob[i*2], "%2hhx", &ablob[i]); + sscanf(&w.hablob[i*2], "%2hhx", &ablob[i]); } } if (ret.err) return ret; - nonsize = wnonce ? strlen(wnonce)*2 : 32; + nonsize = w.nonce ? strlen(w.nonce)*2 : 32; if (nonsize < 32) nonsize = 32; newnonce = alloca(nonsize); - if (wnonce) strcpy(newnonce, wnonce); + if (w.nonce) strcpy(newnonce, w.nonce); else memset(newnonce, 0, nonsize); update_nonce(newnonce, nonsize); - ao = authobj(userid?userid:wuserid, password, - wnonce, newnonce, secret, secsize, + ao = authobj(userid?userid:w.userid, password, + w.nonce, newnonce, secret, secsize, payload, paylsize, ablob, blobsize, fetch_key); @@ -159,41 +211,52 @@ struct _auth_obj authfile(const char *tokenid, return ret; } - if ((fp = fopen(fn, "w"))) { + oldmask = umask(077); + if ((fp = fopen(nfn, "w"))) { int i; - if (fprintf(fp, "%s:%s:%s:", tokenid?tokenid:wtokenid, - userid?userid:wuserid, newnonce) < 0) { + 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) { 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); } } else { ret.err = strerror(errno); } + (void)umask(oldmask); + if (ret.err) { + unlink(nfn); /* may not exist but no matter */ + } else if (rename(nfn, fn)) { + ret.err = strerror(errno); + } if (!ret.err) { - int bufsize = (wuserid?strlen(wuserid)+1:0) + ao.paylsize; + int bufsize = (w.userid?strlen(w.userid)+1:0) + ao.paylsize + 1; if (bufsize) { if ((ret.buffer = malloc(bufsize)) == NULL) { ret.err = "authfile malloc failed"; } else { unsigned char *p = ret.buffer; - if (wuserid) { - strcpy((char*)p, wuserid); + if (w.userid) { + strcpy((char*)p, w.userid); ret.data = p; - ret.datasize = strlen(wuserid)+1; - p += strlen(wuserid)+1; + ret.datasize = strlen(w.userid)+1; + p += strlen(w.userid)+1; } if (ao.payload) { memcpy(p, ao.payload, ao.paylsize); + p[ao.paylsize] = '\0'; ret.payload = p; - ret.paylsize = ao.paylsize; + ret.paylsize = ao.paylsize+1; } } }