1 /* Login code for S/KEY Authentication. S/KEY is a trademark
4 * Mink is the former name of the S/KEY authentication system.
5 * Many references for mink may still be found in this program.
7 * $FreeBSD: src/lib/libskey/skeylogin.c,v 1.14.6.1 2000/07/18 11:38:24 sheldonh Exp $
8 * $DragonFly: src/lib/libskey/skeylogin.c,v 1.4 2004/10/25 19:38:45 drhodus Exp $
11 #include <sys/param.h>
14 #include <sys/resource.h>
24 #include "pathnames.h"
26 static char *skipspace (char *);
28 #define setpriority(x,y,z) /* nothing */
30 static const char *month
[12] = {
31 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
32 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
35 /* Look up skey info for user 'name'. If successful, fill in the caller's
36 * skey structure and return 0. If unsuccessful (e.g., if name is unknown)
37 * return -1. If an optional challenge string buffer is given, update it.
39 * The file read/write pointer is left at the start of the
50 rval
= skeylookup(mp
,name
);
52 case -1: /* File error */
54 case 0: /* Lookup succeeded */
56 sprintf(ss
, "s/key %d %s",mp
->n
- 1,mp
->seed
);
60 case 1: /* User not found */
64 return -1; /* Can't happen */
67 /* Return a skey challenge string for user 'name'. If successful,
68 * fill in the caller's skey structure and return 0. If unsuccessful
69 * (e.g., if name is unknown) return -1.
71 * The file read/write pointer is left at the start of the
75 skeychallenge(mp
,name
, ss
)
82 rval
= skeylookup(mp
,name
);
84 case -1: /* File error */
86 case 0: /* Lookup succeeded, issue challenge */
87 sprintf(ss
, "s/key %d %s",mp
->n
- 1,mp
->seed
);
89 case 1: /* User not found */
93 return -1; /* Can't happen */
96 /* Find an entry in the One-time Password database.
98 * -1: error in opening database
99 * 0: entry found, file R/W pointer positioned at beginning of record
100 * 1: entry not found, file R/W pointer positioned at EOF
114 /* See if the _PATH_SKEYFILE exists, and create it if not */
115 if(stat(_PATH_SKEYFILE
,&statbuf
) == -1 && errno
== ENOENT
){
116 oldmask
= umask(S_IRWXG
|S_IRWXO
);
117 mp
->keyfile
= fopen(_PATH_SKEYFILE
,"w+");
118 (void)umask(oldmask
);
120 /* Otherwise open normally for update */
121 mp
->keyfile
= fopen(_PATH_SKEYFILE
,"r+");
123 if(mp
->keyfile
== NULL
)
126 /* Look up user name in database */
128 if(len
> UT_NAMESIZE
)
131 while(!feof(mp
->keyfile
)){
132 recstart
= ftell(mp
->keyfile
);
133 mp
->recstart
= recstart
;
134 if(fgets(mp
->buf
,sizeof(mp
->buf
),mp
->keyfile
) != mp
->buf
){
138 if(mp
->buf
[0] == '#')
139 continue; /* Comment */
141 while ((cp
= strsep(&p
, " \t")) != NULL
&& *cp
== '\0')
143 if((mp
->logname
= cp
) == NULL
)
145 while ((cp
= strsep(&p
, " \t")) != NULL
&& *cp
== '\0')
150 while ((cp
= strsep(&p
, " \t")) != NULL
&& *cp
== '\0')
152 if((mp
->seed
= cp
) == NULL
)
154 while ((cp
= strsep(&p
, " \t")) != NULL
&& *cp
== '\0')
156 if((mp
->val
= cp
) == NULL
)
158 if(strlen(mp
->logname
) == len
159 && strncmp(mp
->logname
,name
,len
) == 0){
165 fseek(mp
->keyfile
,recstart
,0);
170 /* Verify response to a s/key challenge.
173 * -1: Error of some sort; database unchanged
174 * 0: Verify successful, database updated
175 * 1: Verify failed, database unchanged
177 * The database file is always closed by this call.
180 skeyverify(mp
,response
)
189 char tbuf
[27], fbuf
[20];
193 tm
= localtime(&now
);
194 /* can't use %b here, because it can be in national form */
195 strftime(fbuf
, sizeof(fbuf
), "%d,%Y %T", tm
);
196 snprintf(tbuf
, sizeof(tbuf
), " %s %s", month
[tm
->tm_mon
], fbuf
);
198 if(response
== NULL
){
204 /* Convert response to binary */
205 if(etob(key
,response
) != 1 && atob8(key
,response
) != 0){
206 /* Neither english words or ascii hex */
211 /* Compute fkey = f(key) */
212 memcpy(fkey
,key
,sizeof(key
));
214 /* in order to make the window of update as short as possible
215 we must do the comparison here and if OK write it back
216 other wise the same password can be used twice to get in
220 setpriority(PRIO_PROCESS
, 0, -4);
222 /* reread the file record NOW*/
224 fseek(mp
->keyfile
,mp
->recstart
,0);
225 if(fgets(mp
->buf
,sizeof(mp
->buf
),mp
->keyfile
) != mp
->buf
){
226 setpriority(PRIO_PROCESS
, 0, 0);
232 while ((cp
= strsep(&p
, " \t")) != NULL
&& *cp
== '\0')
235 while ((cp
= strsep(&p
, " \t")) != NULL
&& *cp
== '\0')
237 while ((cp
= strsep(&p
, " \t")) != NULL
&& *cp
== '\0')
240 while ((cp
= strsep(&p
, " \t")) != NULL
&& *cp
== '\0')
243 /* And convert file value to hex for comparison */
244 atob8(filekey
,mp
->val
);
246 /* Do actual comparison */
247 if(memcmp(filekey
,fkey
,8) != 0){
249 setpriority(PRIO_PROCESS
, 0, 0);
254 /* Update key in database by overwriting entire record. Note
255 * that we must write exactly the same number of bytes as in
256 * the original record (note fixed width field for N)
260 fseek(mp
->keyfile
,mp
->recstart
,0);
261 fprintf(mp
->keyfile
,"%s %04d %-16s %s %-21s\n",mp
->logname
,mp
->n
,mp
->seed
,
266 setpriority(PRIO_PROCESS
, 0, 0);
271 /* Convert 8-byte hex-ascii string to binary array
272 * Returns 0 on success, -1 on error
281 if(in
== NULL
|| out
== NULL
)
285 if((in
= skipspace(in
)) == NULL
)
287 if((val
= htoi(*in
++)) == -1)
291 if((in
= skipspace(in
)) == NULL
)
293 if((val
= htoi(*in
++)) == -1)
305 while(*cp
== ' ' || *cp
== '\t')
314 /* Convert 8-byte binary array to hex-ascii string */
321 if(in
== NULL
|| out
== NULL
)
325 sprintf(out
,"%02x",*in
++ & 0xff);
332 /* Convert hex digit to binary integer */
337 if('0' <= c
&& c
<= '9')
339 if('a' <= c
&& c
<= 'f')
341 if('A' <= c
&& c
<= 'F')