Back to index

courier  0.68.2
pcpdauthtoken.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2001 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 
00007 /*
00008 */
00009 
00010 #include      "config.h"
00011 
00012 #if    HAVE_SYS_STAT_H
00013 #include      <sys/stat.h>
00014 #endif
00015 #if HAVE_SYS_WAIT_H
00016 #include      <sys/wait.h>
00017 #endif
00018 
00019 #if    HAVE_UNISTD_H
00020 #include      <unistd.h>
00021 #endif
00022 
00023 #include      <stdio.h>
00024 #include      <stdlib.h>
00025 #include      <ctype.h>
00026 #include      <time.h>
00027 #if    HAVE_UNISTD_H
00028 #include      <unistd.h>
00029 #endif
00030 #include      <string.h>
00031 #include      <errno.h>
00032 
00033 #include      "pcpdauthtoken.h"
00034 #include      "calendardir.h"
00035 #include      "random128/random128.h"
00036 #include      "numlib/numlib.h"
00037 #include      "libhmac/hmac.h"
00038 
00039 static char prev_token[128/8];
00040 static char cur_token[128/8];
00041 static time_t expire_time;
00042 
00043 static const char xdigit[]="0123456789ABCDEF";
00044 
00045 static int nyb(char c)
00046 {
00047        const char *p=strchr(xdigit, c);
00048 
00049        if (!p)
00050               return (-1);
00051        return (p-xdigit);
00052 }
00053 
00054 static int goodtoken(const char *p, char *q)
00055 {
00056        int i;
00057        for (i=0; i<128/8; i++)
00058        {
00059               int a, b;
00060 
00061               if ((a=nyb(*p++)) < 0 || (b=nyb(*p++)) < 0)
00062                      return (-1);
00063 
00064               *q++= a * 16 + b;
00065        }
00066        return (0);
00067 }
00068 
00069 static void newtoken(char *p)
00070 {
00071        const char *q=random128();
00072        int i;
00073 
00074        for (i=0; i<128/8; i++)
00075        {
00076               int a=nyb(*q++);
00077               int b=nyb(*q++);
00078 
00079               *p++ = a * 16 + b;
00080        }
00081 }
00082 
00083 static void savetokens()
00084 {
00085        FILE *fp;
00086 
00087        int i;
00088 
00089        umask(077);
00090        fp=fopen(RANDTOKENFILE ".tmp", "w");
00091        umask(022);
00092 
00093        if (fp)
00094        {
00095               for (i=0; i<128/8; i++)
00096                      fprintf(fp, "%02X", (int)(unsigned char)prev_token[i]);
00097               fprintf(fp, "\n");
00098               for (i=0; i<128/8; i++)
00099                      fprintf(fp, "%02X", (int)(unsigned char)cur_token[i]);
00100               fprintf(fp, "\n");
00101               if (fflush(fp) == 0 && ferror(fp) == 0)
00102               {
00103                      if (fclose(fp) == 0)
00104                      {
00105                             rename(RANDTOKENFILE ".tmp", RANDTOKENFILE);
00106                             return;
00107                      }
00108               }
00109               else
00110                      fclose(fp);
00111        }
00112 
00113        fprintf(stderr, "CRIT: cannot save authentication tokens\n");
00114 }
00115 
00116 void authtoken_init()
00117 {
00118        char buf1[512], buf2[512];
00119        char t1[128/8], t2[128/8];
00120        struct stat stat_buf;
00121 
00122        FILE *fp=fopen(RANDTOKENFILE, "r");
00123 
00124        time(&expire_time);
00125 
00126        if (fp)
00127        {
00128               if (fgets(buf1, sizeof(buf1), fp) &&
00129                   fgets(buf2, sizeof(buf2), fp))
00130               {
00131                      char *p;
00132 
00133                      if ((p=strchr(buf1, '\n')) != NULL)
00134                             *p=0;
00135                      if ((p=strchr(buf2, '\n')) != NULL)
00136                             *p=0;
00137 
00138                      /* Determine if the saved tokens are kosher */
00139 
00140                      if (strlen(buf1) == 32 &&
00141                          strlen(buf2) == 32 &&
00142                          goodtoken(buf1, t1) == 0 &&
00143                          goodtoken(buf2, t2) == 0 &&
00144                          fstat(fileno(fp), &stat_buf) == 0 &&
00145 
00146                          /* Haven't expired (+tolerate clock adjustments) */
00147                          stat_buf.st_mtime < expire_time + 60 &&
00148                          stat_buf.st_mtime >= expire_time - TIMEOUT*2)
00149                      {
00150                             expire_time=stat_buf.st_mtime + TIMEOUT*2;
00151                             memcpy(prev_token, t1, sizeof(t1));
00152                             memcpy(cur_token, t2, sizeof(t2));
00153                             fclose(fp);
00154                             fprintf(stderr, "NOTICE: restored saved authentication tokens\n");
00155                             return;
00156                      }
00157               }
00158               fclose(fp);
00159        }
00160        newtoken(prev_token);
00161        newtoken(cur_token);
00162        expire_time += TIMEOUT*2;
00163        savetokens();
00164 }
00165 
00166 /* Check if authentication tokens have expired */
00167 
00168 time_t authtoken_check()
00169 {
00170        time_t now;
00171 
00172        time(&now);
00173 
00174        if (now < expire_time && now >= expire_time - TIMEOUT*4)
00175               return (expire_time - now);
00176 
00177        memcpy(prev_token, cur_token, sizeof(cur_token));
00178        newtoken(cur_token);
00179        savetokens();
00180        now += TIMEOUT*2;
00181        expire_time=now;
00182        return (TIMEOUT*2);
00183 }
00184 
00185 /*
00186 ** Create a new authentication token.
00187 */
00188 
00189 static char *mktoken(const char *, const char *, time_t);
00190 
00191 char *authtoken_create(const char *userid, time_t now)
00192 {
00193        return (mktoken(userid, cur_token, now));
00194 }
00195 
00196 static char *mktoken(const char *hash, const char *t, time_t now)
00197 {
00198        char now_s[NUMBUFSIZE];
00199        char *p;
00200        unsigned char *q;
00201        int i;
00202        char *r;
00203 
00204        libmail_strh_time_t(now, now_s);
00205 
00206        p=malloc(strlen(hash)+strlen(now_s)+3+hmac_sha1.hh_L*2);
00207 
00208        if (!p)
00209               return (NULL);
00210 
00211        strcat(strcpy(p, hash), now_s);
00212 
00213        q=malloc(hmac_sha1.hh_L*3);
00214 
00215        if (!q)
00216        {
00217               free(p);
00218               return (NULL);
00219        }
00220 
00221        hmac_hashkey(&hmac_sha1, t, sizeof(cur_token),
00222                    q, q + hmac_sha1.hh_L);
00223        hmac_hashtext(&hmac_sha1, p, strlen(p),
00224                     q, q + hmac_sha1.hh_L, q + hmac_sha1.hh_L*2);
00225 
00226        strcpy(p, now_s);
00227        r=p + strlen(p);
00228        *r++='-';
00229 
00230        for (i=0; i<hmac_sha1.hh_L; i++)
00231        {
00232               int c=(unsigned char)q[hmac_sha1.hh_L*2+i];
00233 
00234               *r++ = xdigit[c / 16];
00235               *r++ = xdigit[c % 16];
00236        }
00237        *r=0;
00238        free(q);
00239        return (p);
00240 }
00241 
00242 /*
00243 ** Check if this token is valid.
00244 **
00245 ** Here's what we do: extract time_t from the first part of the token,
00246 ** then run the usrid and time_t against both the current seed, and the
00247 ** previous seed.
00248 */
00249 
00250 int authtoken_verify(const char *userid, const char *token, time_t *when)
00251 {
00252        time_t tval=0;
00253        const char *p=token;
00254        char *q;
00255        time_t now;
00256 
00257        while (*p)
00258        {
00259               int n=nyb(*p);
00260 
00261               if (n < 0)
00262                      break;
00263 
00264               tval *= 16;
00265               tval += n;
00266               ++p;
00267        }
00268 
00269        if (*p != '-' || p != token + sizeof(tval)*2)
00270               return (-1);
00271 
00272        time(&now);
00273        if (tval < now - TIMEOUT*4 || tval > now+60)
00274               return (-1);
00275        *when=tval;
00276 
00277        q=mktoken(userid, cur_token, tval);
00278 
00279        if (q)
00280        {
00281               if (strcmp(q, token) == 0)
00282               {
00283                      free(q);
00284                      return (0);
00285               }
00286               free(q);
00287               q=mktoken(userid, prev_token, tval);
00288 
00289               if (q)
00290               {
00291                      if (strcmp(q, token) == 0)
00292                      {
00293                             free(q);
00294                             return (0);
00295                      }
00296                      free(q);
00297                      return (-1);
00298               }
00299        }
00300 
00301        fprintf(stderr, "CRIT: authtoken_create() failed.\n");
00302        return (-1);
00303 }