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