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.12 nia __RCSID("$NetBSD: sra.c,v 1.12 2021/10/30 10:46:57 nia 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.11 christos static int check_user(char *, const 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.11 christos check_user(char *name, const 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.12 nia struct pam_response *reply = NULL; 521 1.1 christos 522 1.12 nia if (reallocarr(&reply, num_msg, sizeof(*reply)) != 0) 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.11 christos check_user(char *name, const 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