sra.c revision 1.9 1 1.1 christos /*-
2 1.1 christos * Copyright (c) 1991, 1993
3 1.1 christos * Dave Safford. All rights reserved.
4 1.1 christos *
5 1.1 christos * Redistribution and use in source and binary forms, with or without
6 1.1 christos * modification, are permitted provided that the following conditions
7 1.1 christos * are met:
8 1.1 christos * 1. Redistributions of source code must retain the above copyright
9 1.1 christos * notice, this list of conditions and the following disclaimer.
10 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
11 1.1 christos * notice, this list of conditions and the following disclaimer in the
12 1.1 christos * documentation and/or other materials provided with the distribution.
13 1.1 christos * 3. Neither the name of the University nor the names of its contributors
14 1.1 christos * may be used to endorse or promote products derived from this software
15 1.1 christos * without specific prior written permission.
16 1.1 christos *
17 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 1.1 christos * SUCH DAMAGE.
28 1.1 christos *
29 1.1 christos */
30 1.1 christos
31 1.1 christos #include <sys/cdefs.h>
32 1.1 christos #ifdef notdef
33 1.1 christos __FBSDID("$FreeBSD: src/contrib/telnet/libtelnet/sra.c,v 1.16 2002/05/06 09:48:02 markm Exp $");
34 1.1 christos #else
35 1.9 joerg __RCSID("$NetBSD: sra.c,v 1.9 2011/07/01 01:15:27 joerg Exp $");
36 1.1 christos #endif
37 1.1 christos
38 1.1 christos #ifdef SRA
39 1.1 christos #ifdef ENCRYPTION
40 1.1 christos #include <sys/types.h>
41 1.1 christos #include <arpa/telnet.h>
42 1.4 lukem #include <paths.h>
43 1.1 christos #include <pwd.h>
44 1.1 christos #include <stdio.h>
45 1.1 christos #include <stdlib.h>
46 1.1 christos #include <string.h>
47 1.1 christos #include <syslog.h>
48 1.1 christos #include <ttyent.h>
49 1.1 christos
50 1.1 christos #ifndef NOPAM
51 1.1 christos #include <security/pam_appl.h>
52 1.1 christos #else
53 1.1 christos #include <unistd.h>
54 1.1 christos #endif
55 1.1 christos
56 1.1 christos #include "auth.h"
57 1.1 christos #include "misc.h"
58 1.1 christos #include "encrypt.h"
59 1.1 christos #include "pk.h"
60 1.1 christos
61 1.1 christos char pka[HEXKEYBYTES+1], ska[HEXKEYBYTES+1], pkb[HEXKEYBYTES+1];
62 1.1 christos char *user, *pass, *xuser, *xpass;
63 1.7 christos char *passprompt, *xpassprompt;
64 1.1 christos DesData ck;
65 1.1 christos IdeaData ik;
66 1.1 christos
67 1.1 christos extern int auth_debug_mode;
68 1.4 lukem extern char *line; /* see sys_term.c */
69 1.1 christos
70 1.1 christos static int sra_valid = 0;
71 1.1 christos static int passwd_sent = 0;
72 1.1 christos
73 1.1 christos static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
74 1.1 christos AUTHTYPE_SRA, };
75 1.1 christos
76 1.1 christos #define SRA_KEY 0
77 1.1 christos #define SRA_USER 1
78 1.1 christos #define SRA_CONTINUE 2
79 1.1 christos #define SRA_PASS 3
80 1.1 christos #define SRA_ACCEPT 4
81 1.1 christos #define SRA_REJECT 5
82 1.1 christos
83 1.1 christos static int check_user(char *, char *);
84 1.1 christos
85 1.1 christos /* support routine to send out authentication message */
86 1.1 christos static int
87 1.1 christos Data(Authenticator *ap, int type, void *d, int c)
88 1.1 christos {
89 1.1 christos unsigned char *p = str_data + 4;
90 1.1 christos unsigned char *cd = (unsigned char *)d;
91 1.1 christos
92 1.1 christos if (c == -1)
93 1.1 christos c = strlen((char *)cd);
94 1.1 christos
95 1.1 christos if (auth_debug_mode) {
96 1.1 christos printf("%s:%d: [%d] (%d)",
97 1.1 christos str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
98 1.1 christos str_data[3],
99 1.1 christos type, c);
100 1.1 christos printd(d, c);
101 1.1 christos printf("\r\n");
102 1.1 christos }
103 1.1 christos *p++ = ap->type;
104 1.1 christos *p++ = ap->way;
105 1.1 christos *p++ = type;
106 1.1 christos while (c-- > 0) {
107 1.1 christos if ((*p++ = *cd++) == IAC)
108 1.1 christos *p++ = IAC;
109 1.1 christos }
110 1.1 christos *p++ = IAC;
111 1.1 christos *p++ = SE;
112 1.1 christos if (str_data[3] == TELQUAL_IS)
113 1.1 christos printsub('>', &str_data[2], p - (&str_data[2]));
114 1.1 christos return(telnet_net_write(str_data, p - str_data));
115 1.1 christos }
116 1.1 christos
117 1.1 christos int
118 1.1 christos sra_init(Authenticator *ap __unused, int server)
119 1.1 christos {
120 1.1 christos if (server)
121 1.1 christos str_data[3] = TELQUAL_REPLY;
122 1.1 christos else
123 1.1 christos str_data[3] = TELQUAL_IS;
124 1.1 christos
125 1.1 christos user = (char *)malloc(256);
126 1.1 christos xuser = (char *)malloc(513);
127 1.1 christos pass = (char *)malloc(256);
128 1.1 christos xpass = (char *)malloc(513);
129 1.7 christos passprompt = (char *)malloc(256);
130 1.7 christos xpassprompt = (char *)malloc(513);
131 1.1 christos
132 1.1 christos if (user == NULL || xuser == NULL || pass == NULL || xpass ==
133 1.7 christos NULL || passprompt == NULL || xpassprompt == NULL)
134 1.1 christos return 0; /* malloc failed */
135 1.1 christos
136 1.1 christos passwd_sent = 0;
137 1.1 christos
138 1.1 christos genkeys(pka,ska);
139 1.1 christos return(1);
140 1.1 christos }
141 1.1 christos
142 1.1 christos /* client received a go-ahead for sra */
143 1.1 christos int
144 1.1 christos sra_send(Authenticator *ap)
145 1.1 christos {
146 1.1 christos /* send PKA */
147 1.1 christos
148 1.1 christos if (auth_debug_mode)
149 1.1 christos printf("Sent PKA to server.\r\n" );
150 1.1 christos printf("Trying SRA secure login:\r\n");
151 1.1 christos if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
152 1.1 christos if (auth_debug_mode)
153 1.1 christos printf("Not enough room for authentication data\r\n");
154 1.1 christos return(0);
155 1.1 christos }
156 1.1 christos
157 1.1 christos return(1);
158 1.1 christos }
159 1.1 christos
160 1.1 christos /* server received an IS -- could be SRA KEY, USER, or PASS */
161 1.1 christos void
162 1.1 christos sra_is(Authenticator *ap, unsigned char *data, int cnt)
163 1.1 christos {
164 1.1 christos int valid;
165 1.1 christos Session_Key skey;
166 1.1 christos
167 1.1 christos if (cnt-- < 1)
168 1.1 christos goto bad;
169 1.1 christos switch (*data++) {
170 1.1 christos
171 1.1 christos case SRA_KEY:
172 1.1 christos if (cnt < HEXKEYBYTES) {
173 1.1 christos Data(ap, SRA_REJECT, (void *)0, 0);
174 1.1 christos auth_finished(ap, AUTH_USER);
175 1.1 christos if (auth_debug_mode) {
176 1.1 christos printf("SRA user rejected for bad PKB\r\n");
177 1.1 christos }
178 1.1 christos return;
179 1.1 christos }
180 1.1 christos if (auth_debug_mode)
181 1.1 christos printf("Sent pka\r\n");
182 1.1 christos if (!Data(ap, SRA_KEY, (void *)pka, HEXKEYBYTES)) {
183 1.1 christos if (auth_debug_mode)
184 1.1 christos printf("Not enough room\r\n");
185 1.1 christos return;
186 1.1 christos }
187 1.1 christos memcpy(pkb,data,HEXKEYBYTES);
188 1.1 christos pkb[HEXKEYBYTES] = '\0';
189 1.1 christos common_key(ska,pkb,&ik,&ck);
190 1.1 christos return;
191 1.1 christos
192 1.1 christos case SRA_USER:
193 1.1 christos /* decode KAB(u) */
194 1.1 christos if (cnt > 512) /* Attempted buffer overflow */
195 1.1 christos break;
196 1.1 christos memcpy(xuser,data,cnt);
197 1.1 christos xuser[cnt] = '\0';
198 1.1 christos pk_decode(xuser,user,&ck);
199 1.1 christos auth_encrypt_user(user);
200 1.7 christos #ifndef NOPAM
201 1.7 christos (void)check_user(user, "*");
202 1.7 christos #endif
203 1.7 christos pk_encode(passprompt,xpassprompt,&ck);
204 1.7 christos Data(ap, SRA_CONTINUE, (void *)xpassprompt, 512);
205 1.1 christos
206 1.1 christos return;
207 1.1 christos
208 1.1 christos case SRA_PASS:
209 1.1 christos if (cnt > 512) /* Attempted buffer overflow */
210 1.1 christos break;
211 1.1 christos /* decode KAB(P) */
212 1.1 christos memcpy(xpass,data,cnt);
213 1.1 christos xpass[cnt] = '\0';
214 1.1 christos pk_decode(xpass,pass,&ck);
215 1.1 christos
216 1.1 christos /* check user's password */
217 1.1 christos valid = check_user(user,pass);
218 1.1 christos
219 1.1 christos if(valid) {
220 1.5 lukem /* PAM (via check_user()) may have changed 'user' */
221 1.5 lukem auth_encrypt_user(user);
222 1.1 christos Data(ap, SRA_ACCEPT, (void *)0, 0);
223 1.1 christos skey.data = ck;
224 1.1 christos skey.type = SK_DES;
225 1.1 christos skey.length = 8;
226 1.1 christos encrypt_session_key(&skey, 1);
227 1.1 christos
228 1.1 christos sra_valid = 1;
229 1.1 christos auth_finished(ap, AUTH_VALID);
230 1.1 christos if (auth_debug_mode) {
231 1.1 christos printf("SRA user accepted\r\n");
232 1.1 christos }
233 1.1 christos }
234 1.1 christos else {
235 1.7 christos pk_encode(passprompt,xpassprompt,&ck);
236 1.7 christos Data(ap, SRA_CONTINUE, (void *)xpassprompt, 512);
237 1.1 christos /*
238 1.1 christos Data(ap, SRA_REJECT, (void *)0, 0);
239 1.1 christos sra_valid = 0;
240 1.1 christos auth_finished(ap, AUTH_REJECT);
241 1.1 christos */
242 1.1 christos if (auth_debug_mode) {
243 1.1 christos printf("SRA user failed\r\n");
244 1.1 christos }
245 1.1 christos }
246 1.1 christos return;
247 1.1 christos
248 1.1 christos default:
249 1.1 christos if (auth_debug_mode)
250 1.1 christos printf("Unknown SRA option %d\r\n", data[-1]);
251 1.1 christos }
252 1.1 christos bad:
253 1.1 christos Data(ap, SRA_REJECT, 0, 0);
254 1.1 christos sra_valid = 0;
255 1.1 christos auth_finished(ap, AUTH_REJECT);
256 1.1 christos }
257 1.1 christos
258 1.1 christos /* client received REPLY -- could be SRA KEY, CONTINUE, ACCEPT, or REJECT */
259 1.1 christos void
260 1.1 christos sra_reply(Authenticator *ap, unsigned char *data, int cnt)
261 1.1 christos {
262 1.1 christos char uprompt[256],tuser[256];
263 1.1 christos Session_Key skey;
264 1.1 christos size_t i;
265 1.1 christos
266 1.1 christos if (cnt-- < 1)
267 1.1 christos return;
268 1.1 christos switch (*data++) {
269 1.1 christos
270 1.1 christos case SRA_KEY:
271 1.1 christos /* calculate common key */
272 1.1 christos if (cnt < HEXKEYBYTES) {
273 1.1 christos if (auth_debug_mode) {
274 1.1 christos printf("SRA user rejected for bad PKB\r\n");
275 1.1 christos }
276 1.1 christos return;
277 1.1 christos }
278 1.1 christos memcpy(pkb,data,HEXKEYBYTES);
279 1.1 christos pkb[HEXKEYBYTES] = '\0';
280 1.1 christos
281 1.1 christos common_key(ska,pkb,&ik,&ck);
282 1.1 christos
283 1.1 christos enc_user:
284 1.1 christos
285 1.1 christos /* encode user */
286 1.1 christos memset(tuser,0,sizeof(tuser));
287 1.1 christos sprintf(uprompt,"User (%s): ",UserNameRequested);
288 1.7 christos if (telnet_gets(uprompt,tuser,255,1) == NULL) {
289 1.7 christos printf("\n");
290 1.7 christos exit(1);
291 1.7 christos }
292 1.1 christos if (tuser[0] == '\n' || tuser[0] == '\r' )
293 1.1 christos strcpy(user,UserNameRequested);
294 1.1 christos else {
295 1.1 christos /* telnet_gets leaves the newline on */
296 1.1 christos for(i=0;i<sizeof(tuser);i++) {
297 1.1 christos if (tuser[i] == '\n') {
298 1.1 christos tuser[i] = '\0';
299 1.1 christos break;
300 1.1 christos }
301 1.1 christos }
302 1.1 christos strcpy(user,tuser);
303 1.1 christos }
304 1.1 christos pk_encode(user,xuser,&ck);
305 1.1 christos
306 1.1 christos /* send it off */
307 1.1 christos if (auth_debug_mode)
308 1.1 christos printf("Sent KAB(U)\r\n");
309 1.1 christos if (!Data(ap, SRA_USER, (void *)xuser, strlen(xuser))) {
310 1.1 christos if (auth_debug_mode)
311 1.1 christos printf("Not enough room\r\n");
312 1.1 christos return;
313 1.1 christos }
314 1.1 christos break;
315 1.1 christos
316 1.1 christos case SRA_CONTINUE:
317 1.1 christos if (passwd_sent) {
318 1.1 christos passwd_sent = 0;
319 1.1 christos printf("[ SRA login failed ]\r\n");
320 1.1 christos goto enc_user;
321 1.1 christos }
322 1.8 christos if (cnt > 512) {
323 1.7 christos break;
324 1.8 christos } else if (cnt > 0) {
325 1.8 christos (void)memcpy(xpassprompt,data,cnt);
326 1.8 christos pk_decode(xpassprompt, passprompt, &ck);
327 1.8 christos } else {
328 1.8 christos (void)strcpy(passprompt, "Password: ");
329 1.8 christos }
330 1.1 christos /* encode password */
331 1.9 joerg memset(pass,0,256);
332 1.7 christos if (telnet_gets(passprompt,pass,255,0) == NULL) {
333 1.7 christos printf("\n");
334 1.7 christos exit(1);
335 1.7 christos }
336 1.1 christos pk_encode(pass,xpass,&ck);
337 1.1 christos /* send it off */
338 1.1 christos if (auth_debug_mode)
339 1.1 christos printf("Sent KAB(P)\r\n");
340 1.1 christos if (!Data(ap, SRA_PASS, (void *)xpass, strlen(xpass))) {
341 1.1 christos if (auth_debug_mode)
342 1.1 christos printf("Not enough room\r\n");
343 1.1 christos return;
344 1.1 christos }
345 1.1 christos passwd_sent = 1;
346 1.1 christos break;
347 1.1 christos
348 1.1 christos case SRA_REJECT:
349 1.1 christos printf("[ SRA refuses authentication ]\r\n");
350 1.1 christos printf("Trying plaintext login:\r\n");
351 1.1 christos auth_finished(0,AUTH_REJECT);
352 1.1 christos return;
353 1.1 christos
354 1.1 christos case SRA_ACCEPT:
355 1.1 christos printf("[ SRA accepts you ]\r\n");
356 1.1 christos skey.data = ck;
357 1.1 christos skey.type = SK_DES;
358 1.1 christos skey.length = 8;
359 1.1 christos encrypt_session_key(&skey, 0);
360 1.1 christos
361 1.1 christos auth_finished(ap, AUTH_VALID);
362 1.1 christos return;
363 1.1 christos default:
364 1.1 christos if (auth_debug_mode)
365 1.1 christos printf("Unknown SRA option %d\r\n", data[-1]);
366 1.1 christos return;
367 1.1 christos }
368 1.1 christos }
369 1.1 christos
370 1.1 christos int
371 1.1 christos sra_status(Authenticator *ap __unused, char *name, size_t len, int level)
372 1.1 christos {
373 1.1 christos if (level < AUTH_USER)
374 1.1 christos return(level);
375 1.1 christos if (UserNameRequested && sra_valid) {
376 1.1 christos strlcpy(name, UserNameRequested, len);
377 1.1 christos return(AUTH_VALID);
378 1.1 christos } else
379 1.1 christos return(AUTH_USER);
380 1.1 christos }
381 1.1 christos
382 1.1 christos #define BUMP(buf, len) while (*(buf)) {++(buf), --(len);}
383 1.1 christos #define ADDC(buf, len, c) if ((len) > 0) {*(buf)++ = (c); --(len);}
384 1.1 christos
385 1.1 christos void
386 1.1 christos sra_printsub(unsigned char *data, int cnt, unsigned char *buf, int buflen)
387 1.1 christos {
388 1.1 christos char lbuf[32];
389 1.1 christos int i;
390 1.1 christos
391 1.1 christos buf[buflen-1] = '\0'; /* make sure its NULL terminated */
392 1.1 christos buflen -= 1;
393 1.1 christos
394 1.1 christos switch(data[3]) {
395 1.1 christos
396 1.1 christos case SRA_CONTINUE:
397 1.1 christos strncpy((char *)buf, " CONTINUE ", buflen);
398 1.1 christos goto common;
399 1.1 christos
400 1.1 christos case SRA_REJECT: /* Rejected (reason might follow) */
401 1.1 christos strncpy((char *)buf, " REJECT ", buflen);
402 1.1 christos goto common;
403 1.1 christos
404 1.1 christos case SRA_ACCEPT: /* Accepted (name might follow) */
405 1.1 christos strncpy((char *)buf, " ACCEPT ", buflen);
406 1.1 christos
407 1.1 christos common:
408 1.1 christos BUMP(buf, buflen);
409 1.1 christos if (cnt <= 4)
410 1.1 christos break;
411 1.1 christos ADDC(buf, buflen, '"');
412 1.1 christos for (i = 4; i < cnt; i++)
413 1.1 christos ADDC(buf, buflen, data[i]);
414 1.1 christos ADDC(buf, buflen, '"');
415 1.1 christos ADDC(buf, buflen, '\0');
416 1.1 christos break;
417 1.1 christos
418 1.1 christos case SRA_KEY: /* Authentication data follows */
419 1.1 christos strncpy((char *)buf, " KEY ", buflen);
420 1.1 christos goto common2;
421 1.1 christos
422 1.1 christos case SRA_USER:
423 1.1 christos strncpy((char *)buf, " USER ", buflen);
424 1.1 christos goto common2;
425 1.1 christos
426 1.1 christos case SRA_PASS:
427 1.1 christos strncpy((char *)buf, " PASS ", buflen);
428 1.1 christos goto common2;
429 1.1 christos
430 1.1 christos default:
431 1.1 christos sprintf(lbuf, " %d (unknown)", data[3]);
432 1.1 christos strncpy((char *)buf, lbuf, buflen);
433 1.1 christos common2:
434 1.1 christos BUMP(buf, buflen);
435 1.1 christos for (i = 4; i < cnt; i++) {
436 1.1 christos sprintf(lbuf, " %d", data[i]);
437 1.1 christos strncpy((char *)buf, lbuf, buflen);
438 1.1 christos BUMP(buf, buflen);
439 1.1 christos }
440 1.1 christos break;
441 1.1 christos }
442 1.1 christos }
443 1.1 christos
444 1.6 lukem #ifdef NOPAM
445 1.1 christos static int
446 1.1 christos isroot(const char *usr)
447 1.1 christos {
448 1.2 christos struct passwd pws, *pwd;
449 1.2 christos char pwbuf[1024];
450 1.1 christos
451 1.3 christos if (getpwnam_r(usr, &pws, pwbuf, sizeof(pwbuf), &pwd) != 0 ||
452 1.3 christos pwd == NULL)
453 1.1 christos return 0;
454 1.1 christos return (!pwd->pw_uid);
455 1.1 christos }
456 1.1 christos
457 1.1 christos static int
458 1.4 lukem rootterm(const char *ttyname)
459 1.1 christos {
460 1.1 christos struct ttyent *t;
461 1.4 lukem const char *ttyn;
462 1.4 lukem
463 1.4 lukem ttyn = ttyname;
464 1.4 lukem if (strncmp(ttyn, _PATH_DEV, sizeof(_PATH_DEV)-1) == 0)
465 1.4 lukem ttyn += sizeof(_PATH_DEV) - 1;
466 1.1 christos
467 1.1 christos return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
468 1.1 christos }
469 1.1 christos
470 1.1 christos static int
471 1.1 christos check_user(char *name, char *cred)
472 1.1 christos {
473 1.6 lukem struct passwd pws, *pw;
474 1.6 lukem char pwbuf[1024];
475 1.1 christos char *xpasswd, *salt;
476 1.1 christos
477 1.1 christos if (isroot(name) && !rootterm(line))
478 1.1 christos {
479 1.1 christos crypt("AA","*"); /* Waste some time to simulate success */
480 1.1 christos return(0);
481 1.1 christos }
482 1.1 christos
483 1.6 lukem if (getpwnam_r(name, &pws, pwbuf, sizeof(pwbuf), &pw) == 0 &&
484 1.6 lukem pw != NULL) {
485 1.1 christos if (pw->pw_shell == NULL) {
486 1.1 christos return(0);
487 1.1 christos }
488 1.1 christos
489 1.1 christos salt = pw->pw_passwd;
490 1.1 christos xpasswd = crypt(cred, salt);
491 1.1 christos /* The strcmp does not catch null passwords! */
492 1.6 lukem if (*pw->pw_passwd == '\0' || strcmp(xpasswd, pw->pw_passwd)) {
493 1.1 christos return(0);
494 1.1 christos }
495 1.1 christos return(1);
496 1.1 christos }
497 1.1 christos return(0);
498 1.1 christos }
499 1.6 lukem #else /* !NOPAM */
500 1.1 christos
501 1.1 christos /*
502 1.1 christos * The following is stolen from ftpd, which stole it from the imap-uw
503 1.1 christos * PAM module and login.c. It is needed because we can't really
504 1.1 christos * "converse" with the user, having already gone to the trouble of
505 1.1 christos * getting their username and password through an encrypted channel.
506 1.1 christos */
507 1.1 christos
508 1.1 christos #define COPY_STRING(s) (s ? strdup(s):NULL)
509 1.1 christos
510 1.1 christos struct cred_t {
511 1.1 christos const char *uname;
512 1.1 christos const char *pass;
513 1.1 christos };
514 1.1 christos typedef struct cred_t cred_t;
515 1.1 christos
516 1.1 christos static int
517 1.1 christos auth_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata)
518 1.1 christos {
519 1.1 christos int i;
520 1.1 christos cred_t *cred = (cred_t *) appdata;
521 1.1 christos struct pam_response *reply =
522 1.1 christos malloc(sizeof(struct pam_response) * num_msg);
523 1.1 christos
524 1.1 christos if (reply == NULL)
525 1.1 christos return PAM_BUF_ERR;
526 1.1 christos
527 1.1 christos for (i = 0; i < num_msg; i++) {
528 1.1 christos switch (msg[i]->msg_style) {
529 1.1 christos case PAM_PROMPT_ECHO_ON: /* assume want user name */
530 1.1 christos reply[i].resp_retcode = PAM_SUCCESS;
531 1.1 christos reply[i].resp = COPY_STRING(cred->uname);
532 1.1 christos /* PAM frees resp. */
533 1.1 christos break;
534 1.1 christos case PAM_PROMPT_ECHO_OFF: /* assume want password */
535 1.7 christos (void)strlcpy(passprompt, msg[i]->msg, 256);
536 1.7 christos reply[i].resp_retcode = PAM_SUCCESS;
537 1.7 christos reply[i].resp = COPY_STRING(cred->pass);
538 1.7 christos /* PAM frees resp. */
539 1.7 christos break;
540 1.1 christos case PAM_TEXT_INFO:
541 1.1 christos case PAM_ERROR_MSG:
542 1.1 christos reply[i].resp_retcode = PAM_SUCCESS;
543 1.1 christos reply[i].resp = NULL;
544 1.1 christos break;
545 1.1 christos default: /* unknown message style */
546 1.1 christos free(reply);
547 1.1 christos return PAM_CONV_ERR;
548 1.1 christos }
549 1.1 christos }
550 1.1 christos
551 1.1 christos *resp = reply;
552 1.1 christos return PAM_SUCCESS;
553 1.1 christos }
554 1.1 christos
555 1.1 christos /*
556 1.1 christos * The PAM version as a side effect may put a new username in *name.
557 1.1 christos */
558 1.1 christos static int
559 1.1 christos check_user(char *name, char *cred)
560 1.1 christos {
561 1.1 christos pam_handle_t *pamh = NULL;
562 1.1 christos const void *item;
563 1.1 christos int rval;
564 1.1 christos int e;
565 1.1 christos cred_t auth_cred = { name, cred };
566 1.1 christos struct pam_conv conv = { &auth_conv, &auth_cred };
567 1.1 christos
568 1.1 christos e = pam_start("telnetd", name, &conv, &pamh);
569 1.1 christos if (e != PAM_SUCCESS) {
570 1.1 christos syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e));
571 1.1 christos return 0;
572 1.1 christos }
573 1.1 christos
574 1.1 christos #if 0 /* Where can we find this value? */
575 1.1 christos e = pam_set_item(pamh, PAM_RHOST, remotehost);
576 1.1 christos if (e != PAM_SUCCESS) {
577 1.1 christos syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s",
578 1.1 christos pam_strerror(pamh, e));
579 1.1 christos return 0;
580 1.1 christos }
581 1.1 christos #endif
582 1.1 christos
583 1.1 christos e = pam_authenticate(pamh, 0);
584 1.1 christos switch (e) {
585 1.1 christos case PAM_SUCCESS:
586 1.1 christos /*
587 1.1 christos * With PAM we support the concept of a "template"
588 1.1 christos * user. The user enters a login name which is
589 1.1 christos * authenticated by PAM, usually via a remote service
590 1.1 christos * such as RADIUS or TACACS+. If authentication
591 1.1 christos * succeeds, a different but related "template" name
592 1.1 christos * is used for setting the credentials, shell, and
593 1.1 christos * home directory. The name the user enters need only
594 1.1 christos * exist on the remote authentication server, but the
595 1.1 christos * template name must be present in the local password
596 1.1 christos * database.
597 1.1 christos *
598 1.1 christos * This is supported by two various mechanisms in the
599 1.1 christos * individual modules. However, from the application's
600 1.1 christos * point of view, the template user is always passed
601 1.1 christos * back as a changed value of the PAM_USER item.
602 1.1 christos */
603 1.1 christos if ((e = pam_get_item(pamh, PAM_USER, &item)) ==
604 1.1 christos PAM_SUCCESS) {
605 1.1 christos strcpy(name, item);
606 1.1 christos } else
607 1.1 christos syslog(LOG_ERR, "Couldn't get PAM_USER: %s",
608 1.1 christos pam_strerror(pamh, e));
609 1.6 lukem #if 0 /* pam_securetty(8) should be used to enforce this */
610 1.1 christos if (isroot(name) && !rootterm(line))
611 1.1 christos rval = 0;
612 1.1 christos else
613 1.6 lukem #endif
614 1.1 christos rval = 1;
615 1.1 christos break;
616 1.1 christos
617 1.1 christos case PAM_AUTH_ERR:
618 1.1 christos case PAM_USER_UNKNOWN:
619 1.1 christos case PAM_MAXTRIES:
620 1.1 christos rval = 0;
621 1.1 christos break;
622 1.1 christos
623 1.1 christos default:
624 1.1 christos syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e));
625 1.1 christos rval = 0;
626 1.1 christos break;
627 1.1 christos }
628 1.1 christos
629 1.1 christos if ((e = pam_end(pamh, e)) != PAM_SUCCESS) {
630 1.1 christos syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e));
631 1.1 christos rval = 0;
632 1.1 christos }
633 1.1 christos return rval;
634 1.1 christos }
635 1.1 christos
636 1.6 lukem #endif /* !NOPAM */
637 1.1 christos
638 1.1 christos #endif /* ENCRYPTION */
639 1.1 christos #endif /* SRA */
640