Print this page
10104 pam_set_data() dereferences pointer before checking for NULL
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libpam/pam_framework.c
+++ new/usr/src/lib/libpam/pam_framework.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 +/*
27 + * Copyright (c) 2019, Joyent, Inc.
28 + */
29 +
26 30 #include <syslog.h>
27 31 #include <dlfcn.h>
28 32 #include <sys/types.h>
29 33 #include <sys/stat.h>
30 34 #include <stdlib.h>
31 35 #include <strings.h>
32 36 #include <malloc.h>
33 37 #include <unistd.h>
34 38 #include <fcntl.h>
35 39 #include <errno.h>
36 40
37 41 #include <security/pam_appl.h>
38 42 #include <security/pam_modules.h>
39 43 #include <sys/mman.h>
40 44
41 45 #include <libintl.h>
42 46
43 47 #include "pam_impl.h"
44 48
45 49 static char *pam_snames [PAM_NUM_MODULE_TYPES] = {
46 50 PAM_ACCOUNT_NAME,
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
47 51 PAM_AUTH_NAME,
48 52 PAM_PASSWORD_NAME,
49 53 PAM_SESSION_NAME
50 54 };
51 55
52 56 static char *pam_inames [PAM_MAX_ITEMS] = {
53 57 /* NONE */ NULL,
54 58 /* PAM_SERVICE */ "service",
55 59 /* PAM_USER */ "user",
56 60 /* PAM_TTY */ "tty",
57 -/* PAM_RHOST */ "rhost",
61 +/* PAM_RHOST */ "rhost",
58 62 /* PAM_CONV */ "conv",
59 63 /* PAM_AUTHTOK */ "authtok",
60 64 /* PAM_OLDAUTHTOK */ "oldauthtok",
61 -/* PAM_RUSER */ "ruser",
65 +/* PAM_RUSER */ "ruser",
62 66 /* PAM_USER_PROMPT */ "user_prompt",
63 67 /* PAM_REPOSITORY */ "repository",
64 68 /* PAM_RESOURCE */ "resource",
65 -/* PAM_AUSER */ "auser",
69 +/* PAM_AUSER */ "auser",
66 70 /* Undefined Items */
67 71 };
68 72
69 73 /*
70 74 * This extra definition is needed in order to build this library
71 75 * on pre-64-bit-aware systems.
72 76 */
73 77 #if !defined(_LFS64_LARGEFILE)
74 78 #define stat64 stat
75 79 #endif /* !defined(_LFS64_LARGEFILE) */
76 80
77 81 /* functions to dynamically load modules */
78 82 static int load_modules(pam_handle_t *, int, char *, pamtab_t *);
79 -static void *open_module(pam_handle_t *, char *);
83 +static void *open_module(pam_handle_t *, char *);
80 84 static int load_function(void *, char *, int (**func)());
81 85
82 86 /* functions to read and store the pam.conf configuration file */
83 87 static int open_pam_conf(struct pam_fh **, pam_handle_t *, char *);
84 88 static void close_pam_conf(struct pam_fh *);
85 89 static int read_pam_conf(pam_handle_t *, char *);
86 -static int get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
90 +static int get_pam_conf_entry(struct pam_fh *, pam_handle_t *,
87 91 pamtab_t **);
88 92 static char *read_next_token(char **);
89 93 static char *nextline(struct pam_fh *, pam_handle_t *, int *);
90 94 static int verify_pam_conf(pamtab_t *, char *);
91 95
92 96 /* functions to clean up and free memory */
93 97 static void clean_up(pam_handle_t *);
94 98 static void free_pamconf(pamtab_t *);
95 99 static void free_pam_conf_info(pam_handle_t *);
96 100 static void free_env(env_list *);
97 101
98 102 /* convenience functions for I18N/L10N communication */
99 103
100 104 static void free_resp(int, struct pam_response *);
101 105 static int do_conv(pam_handle_t *, int, int,
102 106 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *,
103 107 struct pam_response **);
104 108
105 109 static int log_priority; /* pam_trace syslog priority & facility */
106 110 static int pam_debug = 0;
107 111
108 112 static char *
109 113 pam_trace_iname(int item_type, char *iname_buf)
110 114 {
111 115 char *name;
112 116
113 117 if (item_type <= 0 ||
114 118 item_type >= PAM_MAX_ITEMS ||
115 119 (name = pam_inames[item_type]) == NULL) {
116 120 (void) sprintf(iname_buf, "%d", item_type);
117 121 return (iname_buf);
118 122 }
119 123 return (name);
120 124 }
121 125
122 126 static char *
123 127 pam_trace_fname(int flag)
124 128 {
125 129 if (flag & PAM_BINDING)
126 130 return (PAM_BINDING_NAME);
127 131 if (flag & PAM_INCLUDE)
128 132 return (PAM_INCLUDE_NAME);
129 133 if (flag & PAM_OPTIONAL)
130 134 return (PAM_OPTIONAL_NAME);
131 135 if (flag & PAM_REQUIRED)
132 136 return (PAM_REQUIRED_NAME);
133 137 if (flag & PAM_REQUISITE)
134 138 return (PAM_REQUISITE_NAME);
135 139 if (flag & PAM_SUFFICIENT)
136 140 return (PAM_SUFFICIENT_NAME);
137 141 return ("bad flag name");
138 142 }
139 143
140 144 static char *
141 145 pam_trace_cname(pam_handle_t *pamh)
142 146 {
143 147 if (pamh->pam_conf_name[pamh->include_depth] == NULL)
144 148 return ("NULL");
145 149 return (pamh->pam_conf_name[pamh->include_depth]);
146 150 }
147 151
148 152 #include <deflt.h>
149 153 #include <stdarg.h>
150 154 /*
151 155 * pam_settrace - setup configuration for pam tracing
152 156 *
153 157 * turn on PAM debug if "magic" file exists
154 158 * if exists (original), pam_debug = PAM_DEBUG_DEFAULT,
155 159 * log_priority = LOG_DEBUG(7) and log_facility = LOG_AUTH(4).
156 160 *
157 161 * if has contents, keywork=value pairs:
158 162 *
159 163 * "log_priority=" 0-7, the pam_trace syslog priority to use
160 164 * (see sys/syslog.h)
161 165 * "log_facility=" 0-23, the pam_trace syslog facility to use
162 166 * (see sys/syslog.h)
163 167 * "debug_flags=" PAM_DEBUG_DEFAULT (0x0001), log traditional
164 168 * (original) debugging.
165 169 * Plus the logical or of:
166 170 * PAM_DEBUG_ITEM (0x0002), log item values and
167 171 * pam_get_item.
168 172 * PAM_DEBUG_MODULE (0x0004), log module return status.
169 173 * PAM_DEBUG_CONF (0x0008), log pam.conf parsing.
170 174 * PAM_DEBUG_DATA (0x0010), get/set_data.
171 175 * PAM_DEBUG_CONV (0x0020), conversation/response.
172 176 *
173 177 * If compiled with DEBUG:
174 178 * PAM_DEBUG_AUTHTOK (0x8000), display AUTHTOK value if
175 179 * PAM_DEBUG_ITEM is set and results from
176 180 * PAM_PROMPT_ECHO_OFF responses.
177 181 * USE CAREFULLY, THIS EXPOSES THE USER'S PASSWORDS.
178 182 *
179 183 * or set to 0 and off even if PAM_DEBUG file exists.
180 184 *
181 185 * Output has the general form:
182 186 * <whatever was set syslog> PAM[<pid>]: <interface>(<handle> and other info)
183 187 * <whatever was set syslog> PAM[<pid>]: details requested for <interface> call
184 188 * Where: <pid> is the process ID of the calling process.
185 189 * <handle> is the Hex value of the pam_handle associated with the
186 190 * call.
187 191 */
188 192
189 193 static void
190 194 pam_settrace()
191 195 {
192 196 void *defp;
193 197
194 198 if ((defp = defopen_r(PAM_DEBUG)) != NULL) {
195 199 char *arg;
196 200 int code;
197 201 int facility = LOG_AUTH;
198 202
199 203 pam_debug = PAM_DEBUG_DEFAULT;
200 204 log_priority = LOG_DEBUG;
201 205
202 206 (void) defcntl_r(DC_SETFLAGS, DC_CASE, defp);
203 207 if ((arg = defread_r(LOG_PRIORITY, defp)) != NULL) {
204 208 code = (int)strtol(arg, NULL, 10);
205 209 if ((code & ~LOG_PRIMASK) == 0) {
206 210 log_priority = code;
207 211 }
208 212 }
209 213 if ((arg = defread_r(LOG_FACILITY, defp)) != NULL) {
210 214 code = (int)strtol(arg, NULL, 10);
211 215 if (code < LOG_NFACILITIES) {
212 216 facility = code << 3;
213 217 }
214 218 }
215 219 if ((arg = defread_r(DEBUG_FLAGS, defp)) != NULL) {
216 220 pam_debug = (int)strtol(arg, NULL, 0);
217 221 }
218 222 defclose_r(defp);
219 223
220 224 log_priority |= facility;
221 225 }
222 226 }
223 227
224 228 /*
225 229 * pam_trace - logs tracing messages
226 230 *
227 231 * flag = debug_flags from /etc/pam_debug
228 232 * format and args = message to print (PAM[<pid>]: is prepended).
229 233 *
230 234 * global log_priority = pam_trace syslog (log_priority | log_facility)
231 235 * from /etc/pam_debug
232 236 */
233 237 /*PRINTFLIKE2*/
234 238 static void
235 239 pam_trace(int flag, char *format, ...)
236 240 {
237 241 va_list args;
238 242 char message[1024];
239 243 int savemask;
240 244
241 245 if ((pam_debug & flag) == 0)
242 246 return;
243 247
244 248 savemask = setlogmask(LOG_MASK(log_priority & LOG_PRIMASK));
245 249 (void) snprintf(message, sizeof (message), "PAM[%ld]: %s",
246 250 (long)getpid(), format);
247 251 va_start(args, format);
248 252 (void) vsyslog(log_priority, message, args);
249 253 va_end(args);
250 254 (void) setlogmask(savemask);
251 255 }
252 256
253 257 /*
254 258 * __pam_log - logs PAM syslog messages
255 259 *
256 260 * priority = message priority
257 261 * format and args = message to log
258 262 */
259 263 /*PRINTFLIKE2*/
260 264 void
261 265 __pam_log(int priority, const char *format, ...)
262 266 {
263 267 va_list args;
264 268 int savemask = setlogmask(LOG_MASK(priority & LOG_PRIMASK));
265 269
266 270 va_start(args, format);
267 271 (void) vsyslog(priority, format, args);
268 272 va_end(args);
269 273 (void) setlogmask(savemask);
270 274 }
271 275
272 276
273 277 /*
274 278 * pam_XXXXX routines
275 279 *
276 280 * These are the entry points to the authentication switch
277 281 */
278 282
279 283 /*
280 284 * pam_start - initiate an authentication transaction and
281 285 * set parameter values to be used during the
282 286 * transaction
283 287 */
284 288
285 289 int
286 290 pam_start(const char *service, const char *user,
287 291 const struct pam_conv *pam_conv, pam_handle_t **pamh)
288 292 {
289 293 int err;
290 294
291 295 *pamh = calloc(1, sizeof (struct pam_handle));
292 296
293 297 pam_settrace();
294 298 pam_trace(PAM_DEBUG_DEFAULT,
295 299 "pam_start(%s,%s,%p:%p) - debug = %x",
296 300 service ? service : "NULL", user ? user : "NULL", (void *)pam_conv,
297 301 (void *)*pamh, pam_debug);
298 302
299 303 if (*pamh == NULL)
300 304 return (PAM_BUF_ERR);
301 305
302 306 (*pamh)->pam_inmodule = RO_OK; /* OK to set RO items */
303 307 if ((err = pam_set_item(*pamh, PAM_SERVICE, (void *)service))
304 308 != PAM_SUCCESS) {
305 309 clean_up(*pamh);
306 310 *pamh = NULL;
307 311 return (err);
308 312 }
309 313
310 314 if ((err = pam_set_item(*pamh, PAM_USER, (void *)user))
311 315 != PAM_SUCCESS) {
312 316 clean_up(*pamh);
313 317 *pamh = NULL;
314 318 return (err);
315 319 }
316 320
317 321 if ((err = pam_set_item(*pamh, PAM_CONV, (void *)pam_conv))
318 322 != PAM_SUCCESS) {
319 323 clean_up(*pamh);
320 324 *pamh = NULL;
321 325 return (err);
322 326 }
323 327
324 328 (*pamh)->pam_inmodule = RW_OK;
325 329 return (PAM_SUCCESS);
326 330 }
327 331
328 332 /*
329 333 * pam_end - terminate an authentication transaction
330 334 */
331 335
332 336 int
333 337 pam_end(pam_handle_t *pamh, int pam_status)
334 338 {
335 339 struct pam_module_data *psd, *p;
336 340 fd_list *expired;
337 341 fd_list *traverse;
338 342 env_list *env_expired;
339 343 env_list *env_traverse;
340 344
341 345 pam_trace(PAM_DEBUG_DEFAULT,
342 346 "pam_end(%p): status = %s", (void *)pamh,
343 347 pam_strerror(pamh, pam_status));
344 348
345 349 if (pamh == NULL)
346 350 return (PAM_SYSTEM_ERR);
347 351
348 352 /* call the cleanup routines for module specific data */
349 353
350 354 psd = pamh->ssd;
351 355 while (psd) {
352 356 if (psd->cleanup) {
353 357 psd->cleanup(pamh, psd->data, pam_status);
354 358 }
355 359 p = psd;
356 360 psd = p->next;
357 361 free(p->module_data_name);
358 362 free(p);
359 363 }
360 364 pamh->ssd = NULL;
361 365
362 366 /* dlclose all module fds */
363 367 traverse = pamh->fd;
364 368 while (traverse) {
365 369 expired = traverse;
366 370 traverse = traverse->next;
367 371 (void) dlclose(expired->mh);
368 372 free(expired);
369 373 }
370 374 pamh->fd = 0;
371 375
372 376 /* remove all environment variables */
373 377 env_traverse = pamh->pam_env;
374 378 while (env_traverse) {
375 379 env_expired = env_traverse;
376 380 env_traverse = env_traverse->next;
377 381 free_env(env_expired);
378 382 }
379 383
380 384 clean_up(pamh);
381 385 return (PAM_SUCCESS);
382 386 }
383 387
384 388 /*
385 389 * pam_set_item - set the value of a parameter that can be
386 390 * retrieved via a call to pam_get_item()
387 391 */
388 392
389 393 int
390 394 pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
391 395 {
392 396 struct pam_item *pip;
393 397 int size;
394 398 char iname_buf[PAM_MAX_MSG_SIZE];
395 399
396 400 if (((pam_debug & PAM_DEBUG_ITEM) == 0) || (pamh == NULL)) {
397 401 pam_trace(PAM_DEBUG_DEFAULT,
398 402 "pam_set_item(%p:%s)", (void *)pamh,
399 403 pam_trace_iname(item_type, iname_buf));
400 404 }
401 405
402 406 if (pamh == NULL)
403 407 return (PAM_SYSTEM_ERR);
404 408
405 409 /* check read only items */
406 410 if ((item_type == PAM_SERVICE) && (pamh->pam_inmodule != RO_OK))
407 411 return (PAM_PERM_DENIED);
408 412
409 413 /*
410 414 * Check that item_type is within valid range
411 415 */
412 416
413 417 if (item_type <= 0 || item_type >= PAM_MAX_ITEMS)
414 418 return (PAM_SYMBOL_ERR);
415 419
416 420 pip = &(pamh->ps_item[item_type]);
417 421
418 422 switch (item_type) {
419 423 case PAM_AUTHTOK:
420 424 case PAM_OLDAUTHTOK:
421 425 if (pip->pi_addr != NULL)
422 426 (void) memset(pip->pi_addr, 0, pip->pi_size);
423 427 /*FALLTHROUGH*/
424 428 case PAM_SERVICE:
425 429 case PAM_USER:
426 430 case PAM_TTY:
427 431 case PAM_RHOST:
428 432 case PAM_RUSER:
429 433 case PAM_USER_PROMPT:
430 434 case PAM_RESOURCE:
431 435 case PAM_AUSER:
432 436 if (pip->pi_addr != NULL) {
433 437 free(pip->pi_addr);
434 438 }
435 439
436 440 if (item == NULL) {
437 441 pip->pi_addr = NULL;
438 442 pip->pi_size = 0;
439 443 } else {
440 444 pip->pi_addr = strdup((char *)item);
441 445 if (pip->pi_addr == NULL) {
442 446 pip->pi_size = 0;
443 447 return (PAM_BUF_ERR);
444 448 }
445 449 pip->pi_size = strlen(pip->pi_addr);
446 450 }
447 451 break;
448 452 case PAM_CONV:
449 453 if (pip->pi_addr != NULL)
450 454 free(pip->pi_addr);
451 455 size = sizeof (struct pam_conv);
452 456 if ((pip->pi_addr = calloc(1, size)) == NULL)
453 457 return (PAM_BUF_ERR);
454 458 if (item != NULL)
455 459 (void) memcpy(pip->pi_addr, item, (unsigned int) size);
456 460 else
457 461 (void) memset(pip->pi_addr, 0, size);
458 462 pip->pi_size = size;
459 463 break;
460 464 case PAM_REPOSITORY:
461 465 if (pip->pi_addr != NULL) {
462 466 pam_repository_t *auth_rep;
463 467
464 468 auth_rep = (pam_repository_t *)pip->pi_addr;
465 469 if (auth_rep->type != NULL)
466 470 free(auth_rep->type);
467 471 if (auth_rep->scope != NULL)
468 472 free(auth_rep->scope);
469 473 free(auth_rep);
470 474 }
471 475 if (item != NULL) {
472 476 pam_repository_t *s, *d;
473 477
474 478 size = sizeof (struct pam_repository);
475 479 pip->pi_addr = calloc(1, size);
476 480 if (pip->pi_addr == NULL)
477 481 return (PAM_BUF_ERR);
478 482
479 483 s = (struct pam_repository *)item;
480 484 d = (struct pam_repository *)pip->pi_addr;
481 485
482 486 d->type = strdup(s->type);
483 487 if (d->type == NULL)
484 488 return (PAM_BUF_ERR);
485 489 d->scope = malloc(s->scope_len);
486 490 if (d->scope == NULL)
487 491 return (PAM_BUF_ERR);
488 492 (void) memcpy(d->scope, s->scope, s->scope_len);
489 493 d->scope_len = s->scope_len;
490 494 }
491 495 pip->pi_size = size;
492 496 break;
493 497 default:
494 498 return (PAM_SYMBOL_ERR);
495 499 }
496 500 switch (item_type) {
497 501 case PAM_CONV:
498 502 pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%p",
499 503 (void *)pamh,
500 504 pam_trace_iname(item_type, iname_buf),
501 505 item ? (void *)((struct pam_conv *)item)->conv :
502 506 (void *)0);
503 507 break;
504 508 case PAM_REPOSITORY:
505 509 pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%s",
506 510 (void *)pamh,
507 511 pam_trace_iname(item_type, iname_buf),
508 512 item ? (((struct pam_repository *)item)->type ?
509 513 ((struct pam_repository *)item)->type : "NULL") :
510 514 "NULL");
511 515 break;
512 516 case PAM_AUTHTOK:
513 517 case PAM_OLDAUTHTOK:
514 518 #ifdef DEBUG
515 519 if (pam_debug & PAM_DEBUG_AUTHTOK)
516 520 pam_trace(PAM_DEBUG_ITEM,
517 521 "pam_set_item(%p:%s)=%s", (void *)pamh,
518 522 pam_trace_iname(item_type, iname_buf),
519 523 item ? (char *)item : "NULL");
520 524 else
521 525 #endif /* DEBUG */
522 526 pam_trace(PAM_DEBUG_ITEM,
523 527 "pam_set_item(%p:%s)=%s", (void *)pamh,
524 528 pam_trace_iname(item_type, iname_buf),
525 529 item ? "********" : "NULL");
526 530 break;
527 531 default:
528 532 pam_trace(PAM_DEBUG_ITEM, "pam_set_item(%p:%s)=%s",
529 533 (void *)pamh,
530 534 pam_trace_iname(item_type, iname_buf),
531 535 item ? (char *)item : "NULL");
532 536 }
533 537
534 538 return (PAM_SUCCESS);
535 539 }
536 540
537 541 /*
538 542 * pam_get_item - read the value of a parameter specified in
539 543 * the call to pam_set_item()
540 544 */
541 545
542 546 int
543 547 pam_get_item(const pam_handle_t *pamh, int item_type, void **item)
544 548 {
545 549 struct pam_item *pip;
546 550 char iname_buf[PAM_MAX_MSG_SIZE];
547 551
548 552 if (((pam_debug & PAM_DEBUG_ITEM) == 0) || (pamh == NULL)) {
549 553 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)",
550 554 (void *)pamh, pam_trace_iname(item_type, iname_buf));
551 555 }
552 556
553 557 if (pamh == NULL)
554 558 return (PAM_SYSTEM_ERR);
555 559
556 560 if (item_type <= 0 || item_type >= PAM_MAX_ITEMS)
557 561 return (PAM_SYMBOL_ERR);
558 562
559 563 if ((pamh->pam_inmodule != WO_OK) &&
560 564 ((item_type == PAM_AUTHTOK || item_type == PAM_OLDAUTHTOK))) {
561 565 __pam_log(LOG_AUTH | LOG_NOTICE, "pam_get_item(%s) called from "
562 566 "a non module context",
563 567 pam_trace_iname(item_type, iname_buf));
564 568 return (PAM_PERM_DENIED);
565 569 }
566 570
567 571 pip = (struct pam_item *)&(pamh->ps_item[item_type]);
568 572
569 573 *item = pip->pi_addr;
570 574 switch (item_type) {
571 575 case PAM_CONV:
572 576 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%p",
573 577 (void *)pamh,
574 578 pam_trace_iname(item_type, iname_buf),
575 579 (void *)((struct pam_conv *)*item)->conv);
576 580 break;
577 581 case PAM_REPOSITORY:
578 582 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%s",
579 583 (void *)pamh,
580 584 pam_trace_iname(item_type, iname_buf),
581 585 *item ? (((struct pam_repository *)*item)->type ?
582 586 ((struct pam_repository *)*item)->type : "NULL") :
583 587 "NULL");
584 588 break;
585 589 case PAM_AUTHTOK:
586 590 case PAM_OLDAUTHTOK:
587 591 #ifdef DEBUG
588 592 if (pam_debug & PAM_DEBUG_AUTHTOK)
589 593 pam_trace(PAM_DEBUG_ITEM,
590 594 "pam_get_item(%p:%s)=%s", (void *)pamh,
591 595 pam_trace_iname(item_type, iname_buf),
592 596 *item ? *(char **)item : "NULL");
593 597 else
594 598 #endif /* DEBUG */
595 599 pam_trace(PAM_DEBUG_ITEM,
596 600 "pam_get_item(%p:%s)=%s", (void *)pamh,
597 601 pam_trace_iname(item_type, iname_buf),
598 602 *item ? "********" : "NULL");
599 603 break;
600 604 default:
601 605 pam_trace(PAM_DEBUG_ITEM, "pam_get_item(%p:%s)=%s",
602 606 (void *)pamh,
603 607 pam_trace_iname(item_type, iname_buf),
604 608 *item ? *(char **)item : "NULL");
605 609 }
606 610
607 611 return (PAM_SUCCESS);
608 612 }
609 613
610 614 /*
611 615 * parse_user_name - process the user response: ignore
612 616 * '\t' or ' ' before or after a user name.
613 617 * user_input is a null terminated string.
614 618 * *ret_username will be the user name.
615 619 */
616 620
617 621 static int
618 622 parse_user_name(char *user_input, char **ret_username)
619 623 {
620 624 register char *ptr;
621 625 register int index = 0;
622 626 char username[PAM_MAX_RESP_SIZE];
623 627
624 628 /* Set the default value for *ret_username */
625 629 *ret_username = NULL;
626 630
627 631 /*
628 632 * Set the initial value for username - this is a buffer holds
629 633 * the user name.
630 634 */
631 635 bzero((void *)username, PAM_MAX_RESP_SIZE);
632 636
633 637 /*
634 638 * The user_input is guaranteed to be terminated by a null character.
635 639 */
636 640 ptr = user_input;
637 641
638 642 /* Skip all the leading whitespaces if there are any. */
639 643 while ((*ptr == ' ') || (*ptr == '\t'))
640 644 ptr++;
641 645
642 646 if (*ptr == '\0') {
643 647 /*
644 648 * We should never get here since the user_input we got
645 649 * in pam_get_user() is not all whitespaces nor just "\0".
646 650 */
647 651 return (PAM_BUF_ERR);
648 652 }
649 653
650 654 /*
651 655 * username will be the first string we get from user_input
652 656 * - we skip leading whitespaces and ignore trailing whitespaces
653 657 */
654 658 while (*ptr != '\0') {
655 659 if ((*ptr == ' ') || (*ptr == '\t'))
656 660 break;
657 661 else {
658 662 username[index] = *ptr;
659 663 index++;
660 664 ptr++;
661 665 }
662 666 }
663 667
664 668 /* ret_username will be freed in pam_get_user(). */
665 669 if ((*ret_username = malloc(index + 1)) == NULL)
666 670 return (PAM_BUF_ERR);
667 671 (void) strcpy(*ret_username, username);
668 672 return (PAM_SUCCESS);
669 673 }
670 674
671 675 /*
672 676 * Get the value of PAM_USER. If not set, then use the convenience function
673 677 * to prompt for the user. Use prompt if specified, else use PAM_USER_PROMPT
674 678 * if it is set, else use default.
675 679 */
676 680 #define WHITESPACE 0
677 681 #define USERNAME 1
678 682
679 683 int
680 684 pam_get_user(pam_handle_t *pamh, char **user, const char *prompt_override)
681 685 {
682 686 int status;
683 687 char *prompt = NULL;
684 688 char *real_username;
685 689 struct pam_response *ret_resp = NULL;
686 690 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
687 691
688 692 pam_trace(PAM_DEBUG_DEFAULT,
689 693 "pam_get_user(%p, %p, %s)", (void *)pamh, (void *)*user,
690 694 prompt_override ? prompt_override : "NULL");
691 695 if (pamh == NULL)
692 696 return (PAM_SYSTEM_ERR);
693 697
694 698 if ((status = pam_get_item(pamh, PAM_USER, (void **)user))
695 699 != PAM_SUCCESS) {
696 700 return (status);
697 701 }
698 702
699 703 /* if the user is set, return it */
700 704
701 705 if (*user != NULL && *user[0] != '\0') {
702 706 return (PAM_SUCCESS);
703 707 }
704 708
705 709 /*
706 710 * if the module is requesting a special prompt, use it.
707 711 * else use PAM_USER_PROMPT.
708 712 */
709 713
710 714 if (prompt_override != NULL) {
711 715 prompt = (char *)prompt_override;
712 716 } else {
713 717 status = pam_get_item(pamh, PAM_USER_PROMPT, (void**)&prompt);
714 718 if (status != PAM_SUCCESS) {
715 719 return (status);
716 720 }
717 721 }
718 722
719 723 /* if the prompt is not set, use default */
720 724
721 725 if (prompt == NULL || prompt[0] == '\0') {
722 726 prompt = dgettext(TEXT_DOMAIN, "Please enter user name: ");
723 727 }
724 728
725 729 /* prompt for the user */
726 730
727 731 (void) strncpy(messages[0], prompt, sizeof (messages[0]));
728 732
729 733 for (;;) {
730 734 int state = WHITESPACE;
731 735
732 736 status = do_conv(pamh, PAM_PROMPT_ECHO_ON, 1, messages,
733 737 NULL, &ret_resp);
734 738
735 739 if (status != PAM_SUCCESS) {
736 740 return (status);
737 741 }
738 742
739 743 if (ret_resp->resp && ret_resp->resp[0] != '\0') {
740 744 int len = strlen(ret_resp->resp);
741 745 int i;
742 746
743 747 for (i = 0; i < len; i++) {
744 748 if ((ret_resp->resp[i] != ' ') &&
745 749 (ret_resp->resp[i] != '\t')) {
746 750 state = USERNAME;
747 751 break;
748 752 }
749 753 }
750 754
751 755 if (state == USERNAME)
752 756 break;
753 757 }
754 758 /* essentially empty response, try again */
755 759 free_resp(1, ret_resp);
756 760 ret_resp = NULL;
757 761 }
758 762
759 763 /* set PAM_USER */
760 764 /* Parse the user input to get the user name. */
761 765 status = parse_user_name(ret_resp->resp, &real_username);
762 766
763 767 if (status != PAM_SUCCESS) {
764 768 if (real_username != NULL)
765 769 free(real_username);
766 770 free_resp(1, ret_resp);
767 771 return (status);
768 772 }
769 773
770 774 status = pam_set_item(pamh, PAM_USER, real_username);
771 775
772 776 free(real_username);
773 777
774 778 free_resp(1, ret_resp);
775 779 if (status != PAM_SUCCESS) {
776 780 return (status);
777 781 }
778 782
779 783 /*
780 784 * finally, get PAM_USER. We have to call pam_get_item to get
781 785 * the value of user because pam_set_item mallocs the memory.
782 786 */
783 787
784 788 status = pam_get_item(pamh, PAM_USER, (void**)user);
785 789 return (status);
786 790 }
787 791
788 792 /*
789 793 * Set module specific data
↓ open down ↓ |
693 lines elided |
↑ open up ↑ |
790 794 */
791 795
792 796 int
793 797 pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data,
794 798 void (*cleanup)(pam_handle_t *pamh, void *data, int pam_end_status))
795 799 {
796 800 struct pam_module_data *psd;
797 801
798 802 pam_trace(PAM_DEBUG_DATA,
799 803 "pam_set_data(%p:%s:%d)=%p", (void *)pamh,
800 - module_data_name ? module_data_name : "NULL", pamh->pam_inmodule,
801 - data);
804 + (module_data_name != NULL) ? module_data_name : "NULL",
805 + (pamh != NULL) ? pamh->pam_inmodule : -1, data);
802 806 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) ||
803 807 module_data_name == NULL) {
804 808 return (PAM_SYSTEM_ERR);
805 809 }
806 810
807 811 /* check if module data already exists */
808 812
809 813 for (psd = pamh->ssd; psd; psd = psd->next) {
810 814 if (strcmp(psd->module_data_name, module_data_name) == 0) {
811 815 /* clean up original data before setting the new data */
812 816 if (psd->cleanup) {
813 817 psd->cleanup(pamh, psd->data, PAM_SUCCESS);
814 818 }
815 819 psd->data = (void *)data;
816 820 psd->cleanup = cleanup;
817 821 return (PAM_SUCCESS);
818 822 }
819 823 }
820 824
821 825 psd = malloc(sizeof (struct pam_module_data));
822 826 if (psd == NULL)
823 827 return (PAM_BUF_ERR);
824 828
825 829 psd->module_data_name = strdup(module_data_name);
826 830 if (psd->module_data_name == NULL) {
827 831 free(psd);
828 832 return (PAM_BUF_ERR);
829 833 }
830 834
831 835 psd->data = (void *)data;
832 836 psd->cleanup = cleanup;
833 837 psd->next = pamh->ssd;
834 838 pamh->ssd = psd;
835 839 return (PAM_SUCCESS);
836 840 }
837 841
838 842 /*
839 843 * get module specific data
840 844 */
841 845
842 846 int
843 847 pam_get_data(const pam_handle_t *pamh, const char *module_data_name,
844 848 const void **data)
845 849 {
846 850 struct pam_module_data *psd;
847 851
848 852 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) ||
849 853 module_data_name == NULL) {
850 854 pam_trace(PAM_DEBUG_DATA,
851 855 "pam_get_data(%p:%s:%d)=%p", (void *)pamh,
852 856 module_data_name ? module_data_name : "NULL",
853 857 pamh->pam_inmodule, *data);
854 858 return (PAM_SYSTEM_ERR);
855 859 }
856 860
857 861 for (psd = pamh->ssd; psd; psd = psd->next) {
858 862 if (strcmp(psd->module_data_name, module_data_name) == 0) {
859 863 *data = psd->data;
860 864 pam_trace(PAM_DEBUG_DATA,
861 865 "pam_get_data(%p:%s)=%p", (void *)pamh,
862 866 module_data_name, *data);
863 867 return (PAM_SUCCESS);
864 868 }
865 869 }
866 870 pam_trace(PAM_DEBUG_DATA,
867 871 "pam_get_data(%p:%s)=%s", (void *)pamh, module_data_name,
868 872 "PAM_NO_MODULE_DATA");
869 873
870 874 return (PAM_NO_MODULE_DATA);
871 875 }
872 876
873 877 /*
874 878 * PAM equivalent to strerror()
875 879 */
876 880 /* ARGSUSED */
877 881 const char *
878 882 pam_strerror(pam_handle_t *pamh, int errnum)
879 883 {
880 884 switch (errnum) {
881 885 case PAM_SUCCESS:
882 886 return (dgettext(TEXT_DOMAIN, "Success"));
883 887 case PAM_OPEN_ERR:
884 888 return (dgettext(TEXT_DOMAIN, "Dlopen failure"));
885 889 case PAM_SYMBOL_ERR:
886 890 return (dgettext(TEXT_DOMAIN, "Symbol not found"));
887 891 case PAM_SERVICE_ERR:
888 892 return (dgettext(TEXT_DOMAIN,
889 893 "Error in underlying service module"));
890 894 case PAM_SYSTEM_ERR:
891 895 return (dgettext(TEXT_DOMAIN, "System error"));
892 896 case PAM_BUF_ERR:
893 897 return (dgettext(TEXT_DOMAIN, "Memory buffer error"));
894 898 case PAM_CONV_ERR:
895 899 return (dgettext(TEXT_DOMAIN, "Conversation failure"));
896 900 case PAM_PERM_DENIED:
897 901 return (dgettext(TEXT_DOMAIN, "Permission denied"));
898 902 case PAM_MAXTRIES:
899 903 return (dgettext(TEXT_DOMAIN,
900 904 "Maximum number of attempts exceeded"));
901 905 case PAM_AUTH_ERR:
902 906 return (dgettext(TEXT_DOMAIN, "Authentication failed"));
903 907 case PAM_NEW_AUTHTOK_REQD:
904 908 return (dgettext(TEXT_DOMAIN, "Get new authentication token"));
905 909 case PAM_CRED_INSUFFICIENT:
906 910 return (dgettext(TEXT_DOMAIN, "Insufficient credentials"));
907 911 case PAM_AUTHINFO_UNAVAIL:
908 912 return (dgettext(TEXT_DOMAIN,
909 913 "Can not retrieve authentication info"));
910 914 case PAM_USER_UNKNOWN:
911 915 return (dgettext(TEXT_DOMAIN, "No account present for user"));
912 916 case PAM_CRED_UNAVAIL:
913 917 return (dgettext(TEXT_DOMAIN,
914 918 "Can not retrieve user credentials"));
915 919 case PAM_CRED_EXPIRED:
916 920 return (dgettext(TEXT_DOMAIN,
917 921 "User credentials have expired"));
918 922 case PAM_CRED_ERR:
919 923 return (dgettext(TEXT_DOMAIN,
920 924 "Failure setting user credentials"));
921 925 case PAM_ACCT_EXPIRED:
922 926 return (dgettext(TEXT_DOMAIN, "User account has expired"));
923 927 case PAM_AUTHTOK_EXPIRED:
924 928 return (dgettext(TEXT_DOMAIN, "User password has expired"));
925 929 case PAM_SESSION_ERR:
926 930 return (dgettext(TEXT_DOMAIN,
927 931 "Can not make/remove entry for session"));
928 932 case PAM_AUTHTOK_ERR:
929 933 return (dgettext(TEXT_DOMAIN,
930 934 "Authentication token manipulation error"));
931 935 case PAM_AUTHTOK_RECOVERY_ERR:
932 936 return (dgettext(TEXT_DOMAIN,
933 937 "Authentication token can not be recovered"));
934 938 case PAM_AUTHTOK_LOCK_BUSY:
935 939 return (dgettext(TEXT_DOMAIN,
936 940 "Authentication token lock busy"));
937 941 case PAM_AUTHTOK_DISABLE_AGING:
938 942 return (dgettext(TEXT_DOMAIN,
939 943 "Authentication token aging disabled"));
940 944 case PAM_NO_MODULE_DATA:
941 945 return (dgettext(TEXT_DOMAIN,
942 946 "Module specific data not found"));
943 947 case PAM_IGNORE:
944 948 return (dgettext(TEXT_DOMAIN, "Ignore module"));
945 949 case PAM_ABORT:
946 950 return (dgettext(TEXT_DOMAIN, "General PAM failure "));
947 951 case PAM_TRY_AGAIN:
948 952 return (dgettext(TEXT_DOMAIN,
949 953 "Unable to complete operation. Try again"));
950 954 default:
951 955 return (dgettext(TEXT_DOMAIN, "Unknown error"));
952 956 }
953 957 }
954 958
955 959 static void *
956 960 sm_name(int ind)
957 961 {
958 962 switch (ind) {
959 963 case PAM_AUTHENTICATE:
960 964 return (PAM_SM_AUTHENTICATE);
961 965 case PAM_SETCRED:
962 966 return (PAM_SM_SETCRED);
963 967 case PAM_ACCT_MGMT:
964 968 return (PAM_SM_ACCT_MGMT);
965 969 case PAM_OPEN_SESSION:
966 970 return (PAM_SM_OPEN_SESSION);
967 971 case PAM_CLOSE_SESSION:
968 972 return (PAM_SM_CLOSE_SESSION);
969 973 case PAM_CHAUTHTOK:
970 974 return (PAM_SM_CHAUTHTOK);
971 975 }
972 976 return (NULL);
973 977 }
974 978
975 979 static int
976 980 (*func(pamtab_t *modulep, int ind))()
977 981 {
978 982 void *funcp;
979 983
980 984 if ((funcp = modulep->function_ptr) == NULL)
981 985 return (NULL);
982 986
983 987 switch (ind) {
984 988 case PAM_AUTHENTICATE:
985 989 return (((struct auth_module *)funcp)->pam_sm_authenticate);
986 990 case PAM_SETCRED:
987 991 return (((struct auth_module *)funcp)->pam_sm_setcred);
988 992 case PAM_ACCT_MGMT:
989 993 return (((struct account_module *)funcp)->pam_sm_acct_mgmt);
990 994 case PAM_OPEN_SESSION:
991 995 return (((struct session_module *)funcp)->pam_sm_open_session);
992 996 case PAM_CLOSE_SESSION:
993 997 return (((struct session_module *)funcp)->pam_sm_close_session);
994 998 case PAM_CHAUTHTOK:
995 999 return (((struct password_module *)funcp)->pam_sm_chauthtok);
996 1000 }
997 1001 return (NULL);
998 1002 }
999 1003
1000 1004 /*
1001 1005 * Run through the PAM service module stack for the given module type.
1002 1006 */
1003 1007 static int
1004 1008 run_stack(pam_handle_t *pamh, int flags, int type, int def_err, int ind,
1005 1009 char *function_name)
1006 1010 {
1007 1011 int err = PAM_SYSTEM_ERR; /* preset */
1008 1012 int optional_error = 0;
1009 1013 int required_error = 0;
1010 1014 int success = 0;
1011 1015 pamtab_t *modulep;
1012 1016 int (*sm_func)();
1013 1017
1014 1018 if (pamh == NULL)
1015 1019 return (PAM_SYSTEM_ERR);
1016 1020
1017 1021 /* read initial entries from pam.conf */
1018 1022 if ((err = read_pam_conf(pamh, PAM_CONFIG)) != PAM_SUCCESS) {
1019 1023 return (err);
1020 1024 }
1021 1025
1022 1026 if ((modulep =
1023 1027 pamh->pam_conf_info[pamh->include_depth][type]) == NULL) {
1024 1028 __pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present",
1025 1029 pam_trace_cname(pamh));
1026 1030 goto exit_return;
1027 1031 }
1028 1032
1029 1033 pamh->pam_inmodule = WO_OK; /* OK to get AUTHTOK */
1030 1034 include:
1031 1035 pam_trace(PAM_DEBUG_MODULE,
1032 1036 "[%d:%s]:run_stack:%s(%p, %x): %s", pamh->include_depth,
1033 1037 pam_trace_cname(pamh), function_name, (void *)pamh, flags,
1034 1038 modulep ? modulep->module_path : "NULL");
1035 1039
1036 1040 while (modulep != NULL) {
1037 1041 if (modulep->pam_flag & PAM_INCLUDE) {
1038 1042 /* save the return location */
1039 1043 pamh->pam_conf_modulep[pamh->include_depth] =
1040 1044 modulep->next;
1041 1045 pam_trace(PAM_DEBUG_MODULE,
1042 1046 "setting for include[%d:%p]",
1043 1047 pamh->include_depth, (void *)modulep->next);
1044 1048 if (pamh->include_depth++ >= PAM_MAX_INCLUDE) {
1045 1049 __pam_log(LOG_AUTH | LOG_ERR,
1046 1050 "run_stack: includes too deep %d "
1047 1051 "found trying to include %s from %s, %d "
1048 1052 "allowed", pamh->include_depth,
1049 1053 modulep->module_path, pamh->pam_conf_name
1050 1054 [PAM_MAX_INCLUDE] == NULL ? "NULL" :
1051 1055 pamh->pam_conf_name[PAM_MAX_INCLUDE],
1052 1056 PAM_MAX_INCLUDE);
1053 1057 goto exit_return;
1054 1058 }
1055 1059 if ((err = read_pam_conf(pamh,
1056 1060 modulep->module_path)) != PAM_SUCCESS) {
1057 1061 __pam_log(LOG_AUTH | LOG_ERR,
1058 1062 "run_stack[%d:%s]: can't read included "
1059 1063 "conf %s", pamh->include_depth,
1060 1064 pam_trace_cname(pamh),
1061 1065 modulep->module_path);
1062 1066 goto exit_return;
1063 1067 }
1064 1068 if ((modulep = pamh->pam_conf_info
1065 1069 [pamh->include_depth][type]) == NULL) {
1066 1070 __pam_log(LOG_AUTH | LOG_ERR,
1067 1071 "run_stack[%d:%s]: no include module "
1068 1072 "present %s", pamh->include_depth,
1069 1073 pam_trace_cname(pamh), function_name);
1070 1074 goto exit_return;
1071 1075 }
1072 1076 if (modulep->pam_flag & PAM_INCLUDE) {
1073 1077 /* first line another include */
1074 1078 goto include;
1075 1079 }
1076 1080 pam_trace(PAM_DEBUG_DEFAULT, "include[%d:%s]"
1077 1081 "(%p, %s)=%s", pamh->include_depth,
1078 1082 pam_trace_cname(pamh), (void *)pamh,
1079 1083 function_name, modulep->module_path);
1080 1084 if ((err = load_modules(pamh, type, sm_name(ind),
1081 1085 pamh->pam_conf_info
1082 1086 [pamh->include_depth][type])) != PAM_SUCCESS) {
1083 1087 pam_trace(PAM_DEBUG_DEFAULT,
1084 1088 "[%d:%s]:%s(%p, %x): load_modules failed",
1085 1089 pamh->include_depth, pam_trace_cname(pamh),
1086 1090 function_name, (void *)pamh, flags);
1087 1091 goto exit_return;
1088 1092 }
1089 1093 if ((modulep = pamh->pam_conf_info
1090 1094 [pamh->include_depth][type]) == NULL) {
1091 1095 __pam_log(LOG_AUTH | LOG_ERR,
1092 1096 "%s no initial module present",
1093 1097 pam_trace_cname(pamh));
1094 1098 goto exit_return;
1095 1099 }
1096 1100 } else if ((err = load_modules(pamh, type, sm_name(ind),
1097 1101 modulep)) != PAM_SUCCESS) {
1098 1102 pam_trace(PAM_DEBUG_DEFAULT,
1099 1103 "[%d:%s]:%s(%p, %x): load_modules failed",
1100 1104 pamh->include_depth, pam_trace_cname(pamh),
1101 1105 function_name, (void *)pamh, flags);
1102 1106 goto exit_return;
1103 1107 } /* PAM_INCLUDE */
1104 1108 sm_func = func(modulep, ind);
1105 1109 if (sm_func) {
1106 1110 err = sm_func(pamh, flags, modulep->module_argc,
1107 1111 (const char **)modulep->module_argv);
1108 1112
1109 1113 pam_trace(PAM_DEBUG_MODULE,
1110 1114 "[%d:%s]:%s(%p, %x): %s returned %s",
1111 1115 pamh->include_depth, pam_trace_cname(pamh),
1112 1116 function_name, (void *)pamh, flags,
1113 1117 modulep->module_path, pam_strerror(pamh, err));
1114 1118
1115 1119 switch (err) {
1116 1120 case PAM_IGNORE:
1117 1121 /* do nothing */
1118 1122 break;
1119 1123 case PAM_SUCCESS:
1120 1124 if ((modulep->pam_flag & PAM_SUFFI_BIND) &&
1121 1125 !required_error) {
1122 1126 pamh->pam_inmodule = RW_OK;
1123 1127 pam_trace(PAM_DEBUG_MODULE,
1124 1128 "[%d:%s]:%s(%p, %x): %s: success",
1125 1129 pamh->include_depth,
1126 1130 pam_trace_cname(pamh),
1127 1131 function_name, (void *)pamh, flags,
1128 1132 (modulep->pam_flag & PAM_BINDING) ?
1129 1133 PAM_BINDING_NAME :
1130 1134 PAM_SUFFICIENT_NAME);
1131 1135 goto exit_return;
1132 1136 }
1133 1137 success = 1;
1134 1138 break;
1135 1139 case PAM_TRY_AGAIN:
1136 1140 /*
1137 1141 * We need to return immediately, and
1138 1142 * we shouldn't reset the AUTHTOK item
1139 1143 * since it is not an error per-se.
1140 1144 */
1141 1145 pamh->pam_inmodule = RW_OK;
1142 1146 pam_trace(PAM_DEBUG_MODULE,
1143 1147 "[%d:%s]:%s(%p, %x): TRY_AGAIN: %s",
1144 1148 pamh->include_depth, pam_trace_cname(pamh),
1145 1149 function_name, (void *)pamh, flags,
1146 1150 pam_strerror(pamh, required_error ?
1147 1151 required_error : err));
1148 1152 err = required_error ? required_error : err;
1149 1153 goto exit_return;
1150 1154 default:
1151 1155 if (modulep->pam_flag & PAM_REQUISITE) {
1152 1156 pamh->pam_inmodule = RW_OK;
1153 1157 pam_trace(PAM_DEBUG_MODULE,
1154 1158 "[%d:%s]:%s(%p, %x): requisite: %s",
1155 1159 pamh->include_depth,
1156 1160 pam_trace_cname(pamh),
1157 1161 function_name, (void *)pamh, flags,
1158 1162 pam_strerror(pamh,
1159 1163 required_error ? required_error :
1160 1164 err));
1161 1165 err = required_error ?
1162 1166 required_error : err;
1163 1167 goto exit_return;
1164 1168 } else if (modulep->pam_flag & PAM_REQRD_BIND) {
1165 1169 if (!required_error)
1166 1170 required_error = err;
1167 1171 } else {
1168 1172 if (!optional_error)
1169 1173 optional_error = err;
1170 1174 }
1171 1175 pam_trace(PAM_DEBUG_DEFAULT,
1172 1176 "[%d:%s]:%s(%p, %x): error %s",
1173 1177 pamh->include_depth, pam_trace_cname(pamh),
1174 1178 function_name, (void *)pamh, flags,
1175 1179 pam_strerror(pamh, err));
1176 1180 break;
1177 1181 }
1178 1182 }
1179 1183 modulep = modulep->next;
1180 1184 }
1181 1185
1182 1186 pam_trace(PAM_DEBUG_MODULE, "[%d:%s]:stack_end:%s(%p, %x): %s %s: %s",
1183 1187 pamh->include_depth, pam_trace_cname(pamh), function_name,
1184 1188 (void *)pamh, flags, pamh->include_depth ? "included" : "final",
1185 1189 required_error ? "required" : success ? "success" :
1186 1190 optional_error ? "optional" : "default",
1187 1191 pam_strerror(pamh, required_error ? required_error :
1188 1192 success ? PAM_SUCCESS : optional_error ? optional_error : def_err));
1189 1193 if (pamh->include_depth > 0) {
1190 1194 free_pam_conf_info(pamh);
1191 1195 pamh->include_depth--;
1192 1196 /* continue at next entry */
1193 1197 modulep = pamh->pam_conf_modulep[pamh->include_depth];
1194 1198 pam_trace(PAM_DEBUG_MODULE, "looping for include[%d:%p]",
1195 1199 pamh->include_depth, (void *)modulep);
1196 1200 goto include;
1197 1201 }
1198 1202 free_pam_conf_info(pamh);
1199 1203 pamh->pam_inmodule = RW_OK;
1200 1204 if (required_error != 0)
1201 1205 return (required_error);
1202 1206 else if (success != 0)
1203 1207 return (PAM_SUCCESS);
1204 1208 else if (optional_error != 0)
1205 1209 return (optional_error);
1206 1210 else
1207 1211 return (def_err);
1208 1212
1209 1213 exit_return:
1210 1214 /*
1211 1215 * All done at whatever depth we're at.
1212 1216 * Go back to not having read /etc/pam.conf
1213 1217 */
1214 1218 while (pamh->include_depth > 0) {
1215 1219 free_pam_conf_info(pamh);
1216 1220 pamh->include_depth--;
1217 1221 }
1218 1222 free_pam_conf_info(pamh);
1219 1223 pamh->pam_inmodule = RW_OK;
1220 1224 return (err);
1221 1225 }
1222 1226
1223 1227 /*
1224 1228 * pam_authenticate - authenticate a user
1225 1229 */
1226 1230
1227 1231 int
1228 1232 pam_authenticate(pam_handle_t *pamh, int flags)
1229 1233 {
1230 1234 int retval;
1231 1235
1232 1236 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_AUTH_ERR,
1233 1237 PAM_AUTHENTICATE, "pam_authenticate");
1234 1238
1235 1239 if (retval != PAM_SUCCESS)
1236 1240 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1237 1241 return (retval);
1238 1242 }
1239 1243
1240 1244 /*
1241 1245 * pam_setcred - modify or retrieve user credentials
1242 1246 */
1243 1247
1244 1248 int
1245 1249 pam_setcred(pam_handle_t *pamh, int flags)
1246 1250 {
1247 1251 int retval;
1248 1252
1249 1253 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_CRED_ERR,
1250 1254 PAM_SETCRED, "pam_setcred");
1251 1255
1252 1256 if (retval != PAM_SUCCESS)
1253 1257 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1254 1258 return (retval);
1255 1259 }
1256 1260
1257 1261 /*
1258 1262 * pam_acct_mgmt - check password aging, account expiration
1259 1263 */
1260 1264
1261 1265 int
1262 1266 pam_acct_mgmt(pam_handle_t *pamh, int flags)
1263 1267 {
1264 1268 int retval;
1265 1269
1266 1270 retval = run_stack(pamh, flags, PAM_ACCOUNT_MODULE, PAM_ACCT_EXPIRED,
1267 1271 PAM_ACCT_MGMT, "pam_acct_mgmt");
1268 1272
1269 1273 if (retval != PAM_SUCCESS &&
1270 1274 retval != PAM_NEW_AUTHTOK_REQD) {
1271 1275 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1272 1276 }
1273 1277 return (retval);
1274 1278 }
1275 1279
1276 1280 /*
1277 1281 * pam_open_session - begin session management
1278 1282 */
1279 1283
1280 1284 int
1281 1285 pam_open_session(pam_handle_t *pamh, int flags)
1282 1286 {
1283 1287 int retval;
1284 1288
1285 1289 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR,
1286 1290 PAM_OPEN_SESSION, "pam_open_session");
1287 1291
1288 1292 if (retval != PAM_SUCCESS)
1289 1293 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1290 1294 return (retval);
1291 1295 }
1292 1296
1293 1297 /*
1294 1298 * pam_close_session - terminate session management
1295 1299 */
1296 1300
1297 1301 int
1298 1302 pam_close_session(pam_handle_t *pamh, int flags)
1299 1303 {
1300 1304 int retval;
1301 1305
1302 1306 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR,
1303 1307 PAM_CLOSE_SESSION, "pam_close_session");
1304 1308
1305 1309 if (retval != PAM_SUCCESS)
1306 1310 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1307 1311 return (retval);
1308 1312 }
1309 1313
1310 1314 /*
1311 1315 * pam_chauthtok - change user authentication token
1312 1316 */
1313 1317
1314 1318 int
1315 1319 pam_chauthtok(pam_handle_t *pamh, int flags)
1316 1320 {
1317 1321 int retval;
1318 1322
1319 1323 /* do not let apps use PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK */
1320 1324 if (flags & (PAM_PRELIM_CHECK | PAM_UPDATE_AUTHTOK)) {
1321 1325 pam_trace(PAM_DEBUG_DEFAULT,
1322 1326 "pam_chauthtok(%p, %x): %s", (void *)pamh, flags,
1323 1327 pam_strerror(pamh, PAM_SYMBOL_ERR));
1324 1328 return (PAM_SYMBOL_ERR);
1325 1329 }
1326 1330
1327 1331 /* 1st pass: PRELIM CHECK */
1328 1332 retval = run_stack(pamh, flags | PAM_PRELIM_CHECK, PAM_PASSWORD_MODULE,
1329 1333 PAM_AUTHTOK_ERR, PAM_CHAUTHTOK, "pam_chauthtok-prelim");
1330 1334
1331 1335 if (retval == PAM_TRY_AGAIN)
1332 1336 return (retval);
1333 1337
1334 1338 if (retval != PAM_SUCCESS) {
1335 1339 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1336 1340 return (retval);
1337 1341 }
1338 1342
1339 1343 /* 2nd pass: UPDATE AUTHTOK */
1340 1344 retval = run_stack(pamh, flags | PAM_UPDATE_AUTHTOK,
1341 1345 PAM_PASSWORD_MODULE, PAM_AUTHTOK_ERR, PAM_CHAUTHTOK,
1342 1346 "pam_chauthtok-update");
1343 1347
1344 1348 if (retval != PAM_SUCCESS)
1345 1349 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1346 1350
1347 1351 return (retval);
1348 1352 }
1349 1353
1350 1354 /*
1351 1355 * pam_putenv - add an environment variable to the PAM handle
1352 1356 * if name_value == 'NAME=VALUE' then set variable to the value
1353 1357 * if name_value == 'NAME=' then set variable to an empty value
1354 1358 * if name_value == 'NAME' then delete the variable
1355 1359 */
1356 1360
1357 1361 int
1358 1362 pam_putenv(pam_handle_t *pamh, const char *name_value)
1359 1363 {
1360 1364 int error = PAM_SYSTEM_ERR;
1361 1365 char *equal_sign = 0;
1362 1366 char *name = NULL, *value = NULL, *tmp_value = NULL;
1363 1367 env_list *traverse, *trail;
1364 1368
1365 1369 pam_trace(PAM_DEBUG_DEFAULT,
1366 1370 "pam_putenv(%p, %s)", (void *)pamh,
1367 1371 name_value ? name_value : "NULL");
1368 1372
1369 1373 if (pamh == NULL || name_value == NULL)
1370 1374 goto out;
1371 1375
1372 1376 /* see if we were passed 'NAME=VALUE', 'NAME=', or 'NAME' */
1373 1377 if ((equal_sign = strchr(name_value, '=')) != 0) {
1374 1378 if ((name = calloc(equal_sign - name_value + 1,
1375 1379 sizeof (char))) == 0) {
1376 1380 error = PAM_BUF_ERR;
1377 1381 goto out;
1378 1382 }
1379 1383 (void) strncpy(name, name_value, equal_sign - name_value);
1380 1384 if ((value = strdup(++equal_sign)) == 0) {
1381 1385 error = PAM_BUF_ERR;
1382 1386 goto out;
1383 1387 }
1384 1388 } else {
1385 1389 if ((name = strdup(name_value)) == 0) {
1386 1390 error = PAM_BUF_ERR;
1387 1391 goto out;
1388 1392 }
1389 1393 }
1390 1394
1391 1395 /* check to see if we already have this variable in the PAM handle */
1392 1396 traverse = pamh->pam_env;
1393 1397 trail = traverse;
1394 1398 while (traverse && strncmp(traverse->name, name, strlen(name))) {
1395 1399 trail = traverse;
1396 1400 traverse = traverse->next;
1397 1401 }
1398 1402
1399 1403 if (traverse) {
1400 1404 /* found a match */
1401 1405 if (value == 0) {
1402 1406 /* remove the env variable */
1403 1407 if (pamh->pam_env == traverse)
1404 1408 pamh->pam_env = traverse->next;
1405 1409 else
1406 1410 trail->next = traverse->next;
1407 1411 free_env(traverse);
1408 1412 } else if (strlen(value) == 0) {
1409 1413 /* set env variable to empty value */
1410 1414 if ((tmp_value = strdup("")) == 0) {
1411 1415 error = PAM_SYSTEM_ERR;
1412 1416 goto out;
1413 1417 }
1414 1418 free(traverse->value);
1415 1419 traverse->value = tmp_value;
1416 1420 } else {
1417 1421 /* set the new value */
1418 1422 if ((tmp_value = strdup(value)) == 0) {
1419 1423 error = PAM_SYSTEM_ERR;
1420 1424 goto out;
1421 1425 }
1422 1426 free(traverse->value);
1423 1427 traverse->value = tmp_value;
1424 1428 }
1425 1429
1426 1430 } else if (traverse == 0 && value) {
1427 1431 /*
1428 1432 * could not find a match in the PAM handle.
1429 1433 * add the new value if there is one
1430 1434 */
1431 1435 if ((traverse = calloc(1, sizeof (env_list))) == 0) {
1432 1436 error = PAM_BUF_ERR;
1433 1437 goto out;
1434 1438 }
1435 1439 if ((traverse->name = strdup(name)) == 0) {
1436 1440 free_env(traverse);
1437 1441 error = PAM_BUF_ERR;
1438 1442 goto out;
1439 1443 }
1440 1444 if ((traverse->value = strdup(value)) == 0) {
1441 1445 free_env(traverse);
1442 1446 error = PAM_BUF_ERR;
1443 1447 goto out;
1444 1448 }
1445 1449 if (trail == 0) {
1446 1450 /* new head of list */
1447 1451 pamh->pam_env = traverse;
1448 1452 } else {
1449 1453 /* adding to end of list */
1450 1454 trail->next = traverse;
1451 1455 }
1452 1456 }
1453 1457
1454 1458 error = PAM_SUCCESS;
1455 1459 out:
1456 1460 if (error != PAM_SUCCESS) {
1457 1461 if (traverse) {
1458 1462 if (traverse->name)
1459 1463 free(traverse->name);
1460 1464 if (traverse->value)
1461 1465 free(traverse->value);
1462 1466 free(traverse);
1463 1467 }
1464 1468 }
1465 1469 if (name)
1466 1470 free(name);
1467 1471 if (value)
1468 1472 free(value);
1469 1473 return (error);
1470 1474 }
1471 1475
1472 1476 /*
1473 1477 * pam_getenv - retrieve an environment variable from the PAM handle
1474 1478 */
1475 1479 char *
1476 1480 pam_getenv(pam_handle_t *pamh, const char *name)
1477 1481 {
1478 1482 int error = PAM_SYSTEM_ERR;
1479 1483 env_list *traverse;
1480 1484
1481 1485 pam_trace(PAM_DEBUG_DEFAULT,
1482 1486 "pam_getenv(%p, %p)", (void *)pamh, (void *)name);
1483 1487
1484 1488 if (pamh == NULL || name == NULL)
1485 1489 goto out;
1486 1490
1487 1491 /* check to see if we already have this variable in the PAM handle */
1488 1492 traverse = pamh->pam_env;
1489 1493 while (traverse && strncmp(traverse->name, name, strlen(name))) {
1490 1494 traverse = traverse->next;
1491 1495 }
1492 1496 error = (traverse ? PAM_SUCCESS : PAM_SYSTEM_ERR);
1493 1497 pam_trace(PAM_DEBUG_DEFAULT,
1494 1498 "pam_getenv(%p, %s)=%s", (void *)pamh, name,
1495 1499 traverse ? traverse->value : "NULL");
1496 1500 out:
1497 1501 return (error ? NULL : strdup(traverse->value));
1498 1502 }
1499 1503
1500 1504 /*
1501 1505 * pam_getenvlist - retrieve all environment variables from the PAM handle
1502 1506 * in a NULL terminated array. On error, return NULL.
1503 1507 */
1504 1508 char **
1505 1509 pam_getenvlist(pam_handle_t *pamh)
1506 1510 {
1507 1511 int error = PAM_SYSTEM_ERR;
1508 1512 char **list = 0;
1509 1513 int length = 0;
1510 1514 env_list *traverse;
1511 1515 char *tenv;
1512 1516 size_t tenv_size;
1513 1517
1514 1518 pam_trace(PAM_DEBUG_DEFAULT,
1515 1519 "pam_getenvlist(%p)", (void *)pamh);
1516 1520
1517 1521 if (pamh == NULL)
1518 1522 goto out;
1519 1523
1520 1524 /* find out how many environment variables we have */
1521 1525 traverse = pamh->pam_env;
1522 1526 while (traverse) {
1523 1527 length++;
1524 1528 traverse = traverse->next;
1525 1529 }
1526 1530
1527 1531 /* allocate the array we will return to the caller */
1528 1532 if ((list = calloc(length + 1, sizeof (char *))) == NULL) {
1529 1533 error = PAM_BUF_ERR;
1530 1534 goto out;
1531 1535 }
1532 1536
1533 1537 /* add the variables one by one */
1534 1538 length = 0;
1535 1539 traverse = pamh->pam_env;
1536 1540 while (traverse != NULL) {
1537 1541 tenv_size = strlen(traverse->name) +
1538 1542 strlen(traverse->value) + 2; /* name=val\0 */
1539 1543 if ((tenv = malloc(tenv_size)) == NULL) {
1540 1544 error = PAM_BUF_ERR;
1541 1545 goto out;
1542 1546 }
1543 1547 /*LINTED*/
1544 1548 (void) sprintf(tenv, "%s=%s", traverse->name, traverse->value);
1545 1549 list[length++] = tenv;
1546 1550 traverse = traverse->next;
1547 1551 }
1548 1552 list[length] = NULL;
1549 1553
1550 1554 error = PAM_SUCCESS;
1551 1555 out:
1552 1556 if (error != PAM_SUCCESS) {
1553 1557 /* free the partially constructed list */
1554 1558 if (list) {
1555 1559 length = 0;
1556 1560 while (list[length] != NULL) {
1557 1561 free(list[length]);
1558 1562 length++;
1559 1563 }
1560 1564 free(list);
1561 1565 }
1562 1566 }
1563 1567 return (error ? NULL : list);
1564 1568 }
1565 1569
1566 1570 /*
1567 1571 * Routines to load a requested module on demand
1568 1572 */
1569 1573
1570 1574 /*
1571 1575 * load_modules - load the requested module.
1572 1576 * if the dlopen or dlsym fail, then
1573 1577 * the module is ignored.
1574 1578 */
1575 1579
1576 1580 static int
1577 1581 load_modules(pam_handle_t *pamh, int type, char *function_name,
1578 1582 pamtab_t *pam_entry)
1579 1583 {
1580 1584 void *mh;
1581 1585 struct auth_module *authp;
1582 1586 struct account_module *accountp;
1583 1587 struct session_module *sessionp;
1584 1588 struct password_module *passwdp;
1585 1589 int loading_functions = 0; /* are we currently loading functions? */
1586 1590
1587 1591 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=%s:%s",
1588 1592 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
1589 1593 function_name, pam_trace_fname(pam_entry->pam_flag),
1590 1594 pam_entry->module_path);
1591 1595
1592 1596 while (pam_entry != NULL) {
1593 1597 pam_trace(PAM_DEBUG_DEFAULT,
1594 1598 "while load_modules[%d:%s](%p, %s)=%s",
1595 1599 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
1596 1600 function_name, pam_entry->module_path);
1597 1601
1598 1602 if (pam_entry->pam_flag & PAM_INCLUDE) {
1599 1603 pam_trace(PAM_DEBUG_DEFAULT,
1600 1604 "done load_modules[%d:%s](%p, %s)=%s",
1601 1605 pamh->include_depth, pam_trace_cname(pamh),
1602 1606 (void *)pamh, function_name,
1603 1607 pam_entry->module_path);
1604 1608 return (PAM_SUCCESS);
1605 1609 }
1606 1610 switch (type) {
1607 1611 case PAM_AUTH_MODULE:
1608 1612
1609 1613 /* if the function has already been loaded, return */
1610 1614 authp = pam_entry->function_ptr;
1611 1615 if (!loading_functions &&
1612 1616 (((strcmp(function_name, PAM_SM_AUTHENTICATE)
1613 1617 == 0) && authp && authp->pam_sm_authenticate) ||
1614 1618 ((strcmp(function_name, PAM_SM_SETCRED) == 0) &&
1615 1619 authp && authp->pam_sm_setcred))) {
1616 1620 return (PAM_SUCCESS);
1617 1621 }
1618 1622
1619 1623 /* function has not been loaded yet */
1620 1624 loading_functions = 1;
1621 1625 if (authp == NULL) {
1622 1626 authp = calloc(1, sizeof (struct auth_module));
1623 1627 if (authp == NULL)
1624 1628 return (PAM_BUF_ERR);
1625 1629 }
1626 1630
1627 1631 /* if open_module fails, return error */
1628 1632 if ((mh = open_module(pamh,
1629 1633 pam_entry->module_path)) == NULL) {
1630 1634 __pam_log(LOG_AUTH | LOG_ERR,
1631 1635 "load_modules[%d:%s]: can not open module "
1632 1636 "%s", pamh->include_depth,
1633 1637 pam_trace_cname(pamh),
1634 1638 pam_entry->module_path);
1635 1639 free(authp);
1636 1640 return (PAM_OPEN_ERR);
1637 1641 }
1638 1642
1639 1643 /* load the authentication function */
1640 1644 if (strcmp(function_name, PAM_SM_AUTHENTICATE) == 0) {
1641 1645 if (load_function(mh, PAM_SM_AUTHENTICATE,
1642 1646 &authp->pam_sm_authenticate)
1643 1647 != PAM_SUCCESS) {
1644 1648 /* return error if dlsym fails */
1645 1649 free(authp);
1646 1650 return (PAM_SYMBOL_ERR);
1647 1651 }
1648 1652
1649 1653 /* load the setcred function */
1650 1654 } else if (strcmp(function_name, PAM_SM_SETCRED) == 0) {
1651 1655 if (load_function(mh, PAM_SM_SETCRED,
1652 1656 &authp->pam_sm_setcred) != PAM_SUCCESS) {
1653 1657 /* return error if dlsym fails */
1654 1658 free(authp);
1655 1659 return (PAM_SYMBOL_ERR);
1656 1660 }
1657 1661 }
1658 1662 pam_entry->function_ptr = authp;
1659 1663 break;
1660 1664 case PAM_ACCOUNT_MODULE:
1661 1665 accountp = pam_entry->function_ptr;
1662 1666 if (!loading_functions &&
1663 1667 (strcmp(function_name, PAM_SM_ACCT_MGMT) == 0) &&
1664 1668 accountp && accountp->pam_sm_acct_mgmt) {
1665 1669 return (PAM_SUCCESS);
1666 1670 }
1667 1671
1668 1672 /*
1669 1673 * If functions are added to the account module,
1670 1674 * verify that one of the other functions hasn't
1671 1675 * already loaded it. See PAM_AUTH_MODULE code.
1672 1676 */
1673 1677 loading_functions = 1;
1674 1678 accountp = calloc(1, sizeof (struct account_module));
1675 1679 if (accountp == NULL)
1676 1680 return (PAM_BUF_ERR);
1677 1681
1678 1682 /* if open_module fails, return error */
1679 1683 if ((mh = open_module(pamh,
1680 1684 pam_entry->module_path)) == NULL) {
1681 1685 __pam_log(LOG_AUTH | LOG_ERR,
1682 1686 "load_modules[%d:%s]: can not open module "
1683 1687 "%s", pamh->include_depth,
1684 1688 pam_trace_cname(pamh),
1685 1689 pam_entry->module_path);
1686 1690 free(accountp);
1687 1691 return (PAM_OPEN_ERR);
1688 1692 }
1689 1693
1690 1694 if (load_function(mh, PAM_SM_ACCT_MGMT,
1691 1695 &accountp->pam_sm_acct_mgmt) != PAM_SUCCESS) {
1692 1696 __pam_log(LOG_AUTH | LOG_ERR,
1693 1697 "load_modules[%d:%s]: pam_sm_acct_mgmt() "
1694 1698 "missing", pamh->include_depth,
1695 1699 pam_trace_cname(pamh));
1696 1700 free(accountp);
1697 1701 return (PAM_SYMBOL_ERR);
1698 1702 }
1699 1703 pam_entry->function_ptr = accountp;
1700 1704 break;
1701 1705 case PAM_SESSION_MODULE:
1702 1706 sessionp = pam_entry->function_ptr;
1703 1707 if (!loading_functions &&
1704 1708 (((strcmp(function_name,
1705 1709 PAM_SM_OPEN_SESSION) == 0) &&
1706 1710 sessionp && sessionp->pam_sm_open_session) ||
1707 1711 ((strcmp(function_name,
1708 1712 PAM_SM_CLOSE_SESSION) == 0) &&
1709 1713 sessionp && sessionp->pam_sm_close_session))) {
1710 1714 return (PAM_SUCCESS);
1711 1715 }
1712 1716
1713 1717 loading_functions = 1;
1714 1718 if (sessionp == NULL) {
1715 1719 sessionp = calloc(1,
1716 1720 sizeof (struct session_module));
1717 1721 if (sessionp == NULL)
1718 1722 return (PAM_BUF_ERR);
1719 1723 }
1720 1724
1721 1725 /* if open_module fails, return error */
1722 1726 if ((mh = open_module(pamh,
1723 1727 pam_entry->module_path)) == NULL) {
1724 1728 __pam_log(LOG_AUTH | LOG_ERR,
1725 1729 "load_modules[%d:%s]: can not open module "
1726 1730 "%s", pamh->include_depth,
1727 1731 pam_trace_cname(pamh),
1728 1732 pam_entry->module_path);
1729 1733 free(sessionp);
1730 1734 return (PAM_OPEN_ERR);
1731 1735 }
1732 1736
1733 1737 if ((strcmp(function_name, PAM_SM_OPEN_SESSION) == 0) &&
1734 1738 load_function(mh, PAM_SM_OPEN_SESSION,
1735 1739 &sessionp->pam_sm_open_session) != PAM_SUCCESS) {
1736 1740 free(sessionp);
1737 1741 return (PAM_SYMBOL_ERR);
1738 1742 } else if ((strcmp(function_name,
1739 1743 PAM_SM_CLOSE_SESSION) == 0) &&
1740 1744 load_function(mh, PAM_SM_CLOSE_SESSION,
1741 1745 &sessionp->pam_sm_close_session) != PAM_SUCCESS) {
1742 1746 free(sessionp);
1743 1747 return (PAM_SYMBOL_ERR);
1744 1748 }
1745 1749 pam_entry->function_ptr = sessionp;
1746 1750 break;
1747 1751 case PAM_PASSWORD_MODULE:
1748 1752 passwdp = pam_entry->function_ptr;
1749 1753 if (!loading_functions &&
1750 1754 (strcmp(function_name, PAM_SM_CHAUTHTOK) == 0) &&
1751 1755 passwdp && passwdp->pam_sm_chauthtok) {
1752 1756 return (PAM_SUCCESS);
1753 1757 }
1754 1758
1755 1759 /*
1756 1760 * If functions are added to the password module,
1757 1761 * verify that one of the other functions hasn't
1758 1762 * already loaded it. See PAM_AUTH_MODULE code.
1759 1763 */
1760 1764 loading_functions = 1;
1761 1765 passwdp = calloc(1, sizeof (struct password_module));
1762 1766 if (passwdp == NULL)
1763 1767 return (PAM_BUF_ERR);
1764 1768
1765 1769 /* if open_module fails, continue */
1766 1770 if ((mh = open_module(pamh,
1767 1771 pam_entry->module_path)) == NULL) {
1768 1772 __pam_log(LOG_AUTH | LOG_ERR,
1769 1773 "load_modules[%d:%s]: can not open module "
1770 1774 "%s", pamh->include_depth,
1771 1775 pam_trace_cname(pamh),
1772 1776 pam_entry->module_path);
1773 1777 free(passwdp);
1774 1778 return (PAM_OPEN_ERR);
1775 1779 }
1776 1780
1777 1781 if (load_function(mh, PAM_SM_CHAUTHTOK,
1778 1782 &passwdp->pam_sm_chauthtok) != PAM_SUCCESS) {
1779 1783 free(passwdp);
1780 1784 return (PAM_SYMBOL_ERR);
1781 1785 }
1782 1786 pam_entry->function_ptr = passwdp;
1783 1787 break;
1784 1788 default:
1785 1789 pam_trace(PAM_DEBUG_DEFAULT,
1786 1790 "load_modules[%d:%s](%p, %s): unsupported type %d",
1787 1791 pamh->include_depth, pam_trace_cname(pamh),
1788 1792 (void *)pamh, function_name, type);
1789 1793 break;
1790 1794 }
1791 1795
1792 1796 pam_entry = pam_entry->next;
1793 1797 } /* while */
1794 1798
1795 1799 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=done",
1796 1800 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
1797 1801 function_name);
1798 1802
1799 1803 return (PAM_SUCCESS);
1800 1804 }
1801 1805
1802 1806 /*
1803 1807 * open_module - Open the module first checking for
1804 1808 * propers modes and ownerships on the file.
1805 1809 */
1806 1810
1807 1811 static void *
1808 1812 open_module(pam_handle_t *pamh, char *module_so)
1809 1813 {
1810 1814 struct stat64 stb;
1811 1815 char *errmsg;
1812 1816 void *lfd;
1813 1817 fd_list *module_fds = 0;
1814 1818 fd_list *trail = 0;
1815 1819 fd_list *traverse = 0;
1816 1820
1817 1821 /* Check the ownership and file modes */
1818 1822 if (stat64(module_so, &stb) < 0) {
1819 1823 __pam_log(LOG_AUTH | LOG_ERR,
1820 1824 "open_module[%d:%s]: stat(%s) failed: %s",
1821 1825 pamh->include_depth, pam_trace_cname(pamh), module_so,
1822 1826 strerror(errno));
1823 1827 return (NULL);
1824 1828 }
1825 1829 if (stb.st_uid != (uid_t)0) {
1826 1830 __pam_log(LOG_AUTH | LOG_ALERT,
1827 1831 "open_module[%d:%s]: Owner of the module %s is not root",
1828 1832 pamh->include_depth, pam_trace_cname(pamh), module_so);
1829 1833 return (NULL);
1830 1834 }
1831 1835 if (stb.st_mode & S_IWGRP) {
1832 1836 __pam_log(LOG_AUTH | LOG_ALERT,
1833 1837 "open_module[%d:%s]: module %s writable by group",
1834 1838 pamh->include_depth, pam_trace_cname(pamh), module_so);
1835 1839 return (NULL);
1836 1840 }
1837 1841 if (stb.st_mode & S_IWOTH) {
1838 1842 __pam_log(LOG_AUTH | LOG_ALERT,
1839 1843 "open_module[%d:%s]: module %s writable by world",
1840 1844 pamh->include_depth, pam_trace_cname(pamh), module_so);
1841 1845 return (NULL);
1842 1846 }
1843 1847
1844 1848 /*
1845 1849 * Perform the dlopen()
1846 1850 */
1847 1851 lfd = (void *)dlopen(module_so, RTLD_LAZY);
1848 1852
1849 1853 if (lfd == NULL) {
1850 1854 errmsg = dlerror();
1851 1855 __pam_log(LOG_AUTH | LOG_ERR, "open_module[%d:%s]: %s "
1852 1856 "failed: %s", pamh->include_depth, pam_trace_cname(pamh),
1853 1857 module_so, errmsg != NULL ? errmsg : "Unknown error");
1854 1858 return (NULL);
1855 1859 } else {
1856 1860 /* add this fd to the pam handle */
1857 1861 if ((module_fds = calloc(1, sizeof (fd_list))) == 0) {
1858 1862 (void) dlclose(lfd);
1859 1863 lfd = 0;
1860 1864 return (NULL);
1861 1865 }
1862 1866 module_fds->mh = lfd;
1863 1867
1864 1868 if (pamh->fd == 0) {
1865 1869 /* adding new head of list */
1866 1870 pamh->fd = module_fds;
1867 1871 } else {
1868 1872 /* appending to end of list */
1869 1873 traverse = pamh->fd;
1870 1874 while (traverse) {
1871 1875 trail = traverse;
1872 1876 traverse = traverse->next;
1873 1877 }
1874 1878 trail->next = module_fds;
1875 1879 }
1876 1880 }
1877 1881
1878 1882 return (lfd);
1879 1883 }
1880 1884
1881 1885 /*
1882 1886 * load_function - call dlsym() to resolve the function address
1883 1887 */
1884 1888 static int
1885 1889 load_function(void *lfd, char *name, int (**func)())
1886 1890 {
1887 1891 char *errmsg = NULL;
1888 1892
1889 1893 if (lfd == NULL)
1890 1894 return (PAM_SYMBOL_ERR);
1891 1895
1892 1896 *func = (int (*)())dlsym(lfd, name);
1893 1897 if (*func == NULL) {
1894 1898 errmsg = dlerror();
1895 1899 __pam_log(LOG_AUTH | LOG_ERR, "dlsym failed %s: error %s",
1896 1900 name, errmsg != NULL ? errmsg : "Unknown error");
1897 1901 return (PAM_SYMBOL_ERR);
1898 1902 }
1899 1903
1900 1904 pam_trace(PAM_DEBUG_DEFAULT,
1901 1905 "load_function: successful load of %s", name);
1902 1906 return (PAM_SUCCESS);
1903 1907 }
1904 1908
1905 1909 /*
1906 1910 * Routines to read the pam.conf configuration file
1907 1911 */
1908 1912
1909 1913 /*
1910 1914 * open_pam_conf - open the pam.conf config file
1911 1915 */
1912 1916
1913 1917 static int
1914 1918 open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config)
1915 1919 {
1916 1920 struct stat64 stb;
1917 1921 int fd;
1918 1922
1919 1923 if ((fd = open(config, O_RDONLY)) == -1) {
1920 1924 __pam_log(LOG_AUTH | LOG_ALERT,
1921 1925 "open_pam_conf[%d:%s]: open(%s) failed: %s",
1922 1926 pamh->include_depth, pam_trace_cname(pamh), config,
1923 1927 strerror(errno));
1924 1928 return (0);
1925 1929 }
1926 1930 /* Check the ownership and file modes */
1927 1931 if (fstat64(fd, &stb) < 0) {
1928 1932 __pam_log(LOG_AUTH | LOG_ALERT,
1929 1933 "open_pam_conf[%d:%s]: stat(%s) failed: %s",
1930 1934 pamh->include_depth, pam_trace_cname(pamh), config,
1931 1935 strerror(errno));
1932 1936 (void) close(fd);
1933 1937 return (0);
1934 1938 }
1935 1939 if (stb.st_uid != (uid_t)0) {
1936 1940 __pam_log(LOG_AUTH | LOG_ALERT,
1937 1941 "open_pam_conf[%d:%s]: Owner of %s is not root",
1938 1942 pamh->include_depth, pam_trace_cname(pamh), config);
1939 1943 (void) close(fd);
1940 1944 return (0);
1941 1945 }
1942 1946 if (stb.st_mode & S_IWGRP) {
1943 1947 __pam_log(LOG_AUTH | LOG_ALERT,
1944 1948 "open_pam_conf[%d:%s]: %s writable by group",
1945 1949 pamh->include_depth, pam_trace_cname(pamh), config);
1946 1950 (void) close(fd);
1947 1951 return (0);
1948 1952 }
1949 1953 if (stb.st_mode & S_IWOTH) {
1950 1954 __pam_log(LOG_AUTH | LOG_ALERT,
1951 1955 "open_pam_conf[%d:%s]: %s writable by world",
1952 1956 pamh->include_depth, pam_trace_cname(pamh), config);
1953 1957 (void) close(fd);
1954 1958 return (0);
1955 1959 }
1956 1960 if ((*pam_fh = calloc(1, sizeof (struct pam_fh))) == NULL) {
1957 1961 (void) close(fd);
1958 1962 return (0);
1959 1963 }
1960 1964 (*pam_fh)->fconfig = fd;
1961 1965 (*pam_fh)->bufsize = (size_t)stb.st_size;
1962 1966 if (((*pam_fh)->data = mmap(0, (*pam_fh)->bufsize, PROT_READ,
1963 1967 MAP_PRIVATE, (*pam_fh)->fconfig, 0)) == MAP_FAILED) {
1964 1968 (void) close(fd);
1965 1969 free (*pam_fh);
1966 1970 return (0);
1967 1971 }
1968 1972 (*pam_fh)->bufferp = (*pam_fh)->data;
1969 1973
1970 1974 return (1);
1971 1975 }
1972 1976
1973 1977 /*
1974 1978 * close_pam_conf - close pam.conf
1975 1979 */
1976 1980
1977 1981 static void
1978 1982 close_pam_conf(struct pam_fh *pam_fh)
1979 1983 {
1980 1984 (void) munmap(pam_fh->data, pam_fh->bufsize);
1981 1985 (void) close(pam_fh->fconfig);
1982 1986 free(pam_fh);
1983 1987 }
1984 1988
1985 1989 /*
1986 1990 * read_pam_conf - read in each entry in pam.conf and store info
1987 1991 * under the pam handle.
1988 1992 */
1989 1993
1990 1994 static int
1991 1995 read_pam_conf(pam_handle_t *pamh, char *config)
1992 1996 {
1993 1997 struct pam_fh *pam_fh;
1994 1998 pamtab_t *pamentp;
1995 1999 pamtab_t *tpament;
1996 2000 char *service;
1997 2001 int error;
1998 2002 int i = pamh->include_depth; /* include depth */
1999 2003 /*
2000 2004 * service types:
2001 2005 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
2002 2006 */
2003 2007 int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0};
2004 2008
2005 2009 (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
2006 2010 if (service == NULL || *service == '\0') {
2007 2011 __pam_log(LOG_AUTH | LOG_ERR, "No service name");
2008 2012 return (PAM_SYSTEM_ERR);
2009 2013 }
2010 2014
2011 2015 pamh->pam_conf_name[i] = strdup(config);
2012 2016 pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)",
2013 2017 i, pam_trace_cname(pamh), (void *)pamh, config);
2014 2018 if (open_pam_conf(&pam_fh, pamh, config) == 0) {
2015 2019 return (PAM_SYSTEM_ERR);
2016 2020 }
2017 2021
2018 2022 while ((error =
2019 2023 get_pam_conf_entry(pam_fh, pamh, &pamentp)) == PAM_SUCCESS &&
2020 2024 pamentp) {
2021 2025
2022 2026 /* See if entry is this service and valid */
2023 2027 if (verify_pam_conf(pamentp, service)) {
2024 2028 pam_trace(PAM_DEBUG_CONF,
2025 2029 "read_pam_conf[%d:%s](%p): bad entry error %s",
2026 2030 i, pam_trace_cname(pamh), (void *)pamh, service);
2027 2031
2028 2032 error = PAM_SYSTEM_ERR;
2029 2033 free_pamconf(pamentp);
2030 2034 goto out;
2031 2035 }
2032 2036 if (strcasecmp(pamentp->pam_service, service) == 0) {
2033 2037 pam_trace(PAM_DEBUG_CONF,
2034 2038 "read_pam_conf[%d:%s](%p): processing %s",
2035 2039 i, pam_trace_cname(pamh), (void *)pamh, service);
2036 2040 /* process first service entry */
2037 2041 if (service_found[pamentp->pam_type + 1] == 0) {
2038 2042 /* purge "other" entries */
2039 2043 while ((tpament = pamh->pam_conf_info[i]
2040 2044 [pamentp->pam_type]) != NULL) {
2041 2045 pam_trace(PAM_DEBUG_CONF,
2042 2046 "read_pam_conf(%p): purging "
2043 2047 "\"other\"[%d:%s][%s]",
2044 2048 (void *)pamh, i,
2045 2049 pam_trace_cname(pamh),
2046 2050 pam_snames[pamentp->pam_type]);
2047 2051 pamh->pam_conf_info[i]
2048 2052 [pamentp->pam_type] = tpament->next;
2049 2053 free_pamconf(tpament);
2050 2054 }
2051 2055 /* add first service entry */
2052 2056 pam_trace(PAM_DEBUG_CONF,
2053 2057 "read_pam_conf(%p): adding 1st "
2054 2058 "%s[%d:%s][%s]",
2055 2059 (void *)pamh, service, i,
2056 2060 pam_trace_cname(pamh),
2057 2061 pam_snames[pamentp->pam_type]);
2058 2062 pamh->pam_conf_info[i][pamentp->pam_type] =
2059 2063 pamentp;
2060 2064 service_found[pamentp->pam_type + 1] = 1;
2061 2065 } else {
2062 2066 /* append more service entries */
2063 2067 pam_trace(PAM_DEBUG_CONF,
2064 2068 "read_pam_conf(%p): adding more "
2065 2069 "%s[%d:%s][%s]",
2066 2070 (void *)pamh, service, i,
2067 2071 pam_trace_cname(pamh),
2068 2072 pam_snames[pamentp->pam_type]);
2069 2073 tpament =
2070 2074 pamh->pam_conf_info[i][pamentp->pam_type];
2071 2075 while (tpament->next != NULL) {
2072 2076 tpament = tpament->next;
2073 2077 }
2074 2078 tpament->next = pamentp;
2075 2079 }
2076 2080 } else if (service_found[pamentp->pam_type + 1] == 0) {
2077 2081 /* See if "other" entry available and valid */
2078 2082 if (verify_pam_conf(pamentp, "other")) {
2079 2083 pam_trace(PAM_DEBUG_CONF,
2080 2084 "read_pam_conf(%p): bad entry error %s "
2081 2085 "\"other\"[%d:%s]",
2082 2086 (void *)pamh, service, i,
2083 2087 pam_trace_cname(pamh));
2084 2088 error = PAM_SYSTEM_ERR;
2085 2089 free_pamconf(pamentp);
2086 2090 goto out;
2087 2091 }
2088 2092 if (strcasecmp(pamentp->pam_service, "other") == 0) {
2089 2093 pam_trace(PAM_DEBUG_CONF,
2090 2094 "read_pam_conf(%p): processing "
2091 2095 "\"other\"[%d:%s]", (void *)pamh, i,
2092 2096 pam_trace_cname(pamh));
2093 2097 if ((tpament = pamh->pam_conf_info[i]
2094 2098 [pamentp->pam_type]) == NULL) {
2095 2099 /* add first "other" entry */
2096 2100 pam_trace(PAM_DEBUG_CONF,
2097 2101 "read_pam_conf(%p): adding 1st "
2098 2102 "other[%d:%s][%s]", (void *)pamh, i,
2099 2103 pam_trace_cname(pamh),
2100 2104 pam_snames[pamentp->pam_type]);
2101 2105 pamh->pam_conf_info[i]
2102 2106 [pamentp->pam_type] = pamentp;
2103 2107 } else {
2104 2108 /* append more "other" entries */
2105 2109 pam_trace(PAM_DEBUG_CONF,
2106 2110 "read_pam_conf(%p): adding more "
2107 2111 "other[%d:%s][%s]", (void *)pamh, i,
2108 2112 pam_trace_cname(pamh),
2109 2113 pam_snames[pamentp->pam_type]);
2110 2114 while (tpament->next != NULL) {
2111 2115 tpament = tpament->next;
2112 2116 }
2113 2117 tpament->next = pamentp;
2114 2118 }
2115 2119 } else {
2116 2120 /* irrelevant entry */
2117 2121 free_pamconf(pamentp);
2118 2122 }
2119 2123 } else {
2120 2124 /* irrelevant entry */
2121 2125 free_pamconf(pamentp);
2122 2126 }
2123 2127 }
2124 2128 out:
2125 2129 (void) close_pam_conf(pam_fh);
2126 2130 if (error != PAM_SUCCESS)
2127 2131 free_pam_conf_info(pamh);
2128 2132 return (error);
2129 2133 }
2130 2134
2131 2135 /*
2132 2136 * get_pam_conf_entry - get a pam.conf entry
2133 2137 */
2134 2138
2135 2139 static int
2136 2140 get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam)
2137 2141 {
2138 2142 char *cp, *arg;
2139 2143 int argc;
2140 2144 char *tmp, *tmp_free;
2141 2145 int i;
2142 2146 char *current_line = NULL;
2143 2147 int error = PAM_SYSTEM_ERR; /* preset to error */
2144 2148 int err;
2145 2149
2146 2150 /* get the next line from pam.conf */
2147 2151 if ((cp = nextline(pam_fh, pamh, &err)) == NULL) {
2148 2152 /* no more lines in pam.conf ==> return */
2149 2153 error = PAM_SUCCESS;
2150 2154 *pam = NULL;
2151 2155 goto out;
2152 2156 }
2153 2157
2154 2158 if ((*pam = calloc(1, sizeof (pamtab_t))) == NULL) {
2155 2159 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2156 2160 goto out;
2157 2161 }
2158 2162
2159 2163 /* copy full line for error reporting */
2160 2164 if ((current_line = strdup(cp)) == NULL) {
2161 2165 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2162 2166 goto out;
2163 2167 }
2164 2168
2165 2169 pam_trace(PAM_DEBUG_CONF,
2166 2170 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line);
2167 2171
2168 2172 /* get service name (e.g. login, su, passwd) */
2169 2173 if ((arg = read_next_token(&cp)) == 0) {
2170 2174 __pam_log(LOG_AUTH | LOG_CRIT,
2171 2175 "illegal pam.conf[%s] entry: %s: missing SERVICE NAME",
2172 2176 pam_trace_cname(pamh), current_line);
2173 2177 goto out;
2174 2178 }
2175 2179 if (((*pam)->pam_service = strdup(arg)) == 0) {
2176 2180 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2177 2181 goto out;
2178 2182 }
2179 2183
2180 2184 /* get module type (e.g. authentication, acct mgmt) */
2181 2185 if ((arg = read_next_token(&cp)) == 0) {
2182 2186 __pam_log(LOG_AUTH | LOG_CRIT,
2183 2187 "illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
2184 2188 pam_trace_cname(pamh), current_line);
2185 2189 (*pam)->pam_type = -1; /* 0 is a valid value */
2186 2190 goto getflag;
2187 2191 }
2188 2192 if (strcasecmp(arg, PAM_AUTH_NAME) == 0) {
2189 2193 (*pam)->pam_type = PAM_AUTH_MODULE;
2190 2194 } else if (strcasecmp(arg, PAM_ACCOUNT_NAME) == 0) {
2191 2195 (*pam)->pam_type = PAM_ACCOUNT_MODULE;
2192 2196 } else if (strcasecmp(arg, PAM_SESSION_NAME) == 0) {
2193 2197 (*pam)->pam_type = PAM_SESSION_MODULE;
2194 2198 } else if (strcasecmp(arg, PAM_PASSWORD_NAME) == 0) {
2195 2199 (*pam)->pam_type = PAM_PASSWORD_MODULE;
2196 2200 } else {
2197 2201 /* error */
2198 2202 __pam_log(LOG_AUTH | LOG_CRIT,
2199 2203 "illegal pam.conf[%s] entry: %s: invalid module "
2200 2204 "type: %s", pam_trace_cname(pamh), current_line, arg);
2201 2205 (*pam)->pam_type = -1; /* 0 is a valid value */
2202 2206 }
2203 2207
2204 2208 getflag:
2205 2209 /* get pam flag (e.g., requisite, required, sufficient, optional) */
2206 2210 if ((arg = read_next_token(&cp)) == 0) {
2207 2211 __pam_log(LOG_AUTH | LOG_CRIT,
2208 2212 "illegal pam.conf[%s] entry: %s: missing CONTROL FLAG",
2209 2213 pam_trace_cname(pamh), current_line);
2210 2214 goto getpath;
2211 2215 }
2212 2216 if (strcasecmp(arg, PAM_BINDING_NAME) == 0) {
2213 2217 (*pam)->pam_flag = PAM_BINDING;
2214 2218 } else if (strcasecmp(arg, PAM_INCLUDE_NAME) == 0) {
2215 2219 (*pam)->pam_flag = PAM_INCLUDE;
2216 2220 } else if (strcasecmp(arg, PAM_OPTIONAL_NAME) == 0) {
2217 2221 (*pam)->pam_flag = PAM_OPTIONAL;
2218 2222 } else if (strcasecmp(arg, PAM_REQUIRED_NAME) == 0) {
2219 2223 (*pam)->pam_flag = PAM_REQUIRED;
2220 2224 } else if (strcasecmp(arg, PAM_REQUISITE_NAME) == 0) {
2221 2225 (*pam)->pam_flag = PAM_REQUISITE;
2222 2226 } else if (strcasecmp(arg, PAM_SUFFICIENT_NAME) == 0) {
2223 2227 (*pam)->pam_flag = PAM_SUFFICIENT;
2224 2228 } else {
2225 2229 /* error */
2226 2230 __pam_log(LOG_AUTH | LOG_CRIT,
2227 2231 "illegal pam.conf[%s] entry: %s",
2228 2232 pam_trace_cname(pamh), current_line);
2229 2233 __pam_log(LOG_AUTH | LOG_CRIT,
2230 2234 "\tinvalid control flag: %s", arg);
2231 2235 }
2232 2236
2233 2237 getpath:
2234 2238 /* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */
2235 2239 if ((arg = read_next_token(&cp)) == 0) {
2236 2240 __pam_log(LOG_AUTH | LOG_CRIT,
2237 2241 "illegal pam.conf[%s] entry: %s: missing MODULE PATH",
2238 2242 pam_trace_cname(pamh), current_line);
2239 2243 error = PAM_SUCCESS; /* success */
2240 2244 goto out;
2241 2245 }
2242 2246 if (arg[0] != '/') {
2243 2247 size_t len;
2244 2248 /*
2245 2249 * If module path does not start with "/", then
2246 2250 * prepend PAM_LIB_DIR (/usr/lib/security/).
2247 2251 */
2248 2252 /* sizeof (PAM_LIB_DIR) has room for '\0' */
2249 2253 len = sizeof (PAM_LIB_DIR) + sizeof (PAM_ISA_DIR) + strlen(arg);
2250 2254 if (((*pam)->module_path = malloc(len)) == NULL) {
2251 2255 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2252 2256 goto out;
2253 2257 }
2254 2258 if ((*pam)->pam_flag & PAM_INCLUDE) {
2255 2259 (void) snprintf((*pam)->module_path, len, "%s%s",
2256 2260 PAM_LIB_DIR, arg);
2257 2261 } else {
2258 2262 (void) snprintf((*pam)->module_path, len, "%s%s%s",
2259 2263 PAM_LIB_DIR, PAM_ISA_DIR, arg);
2260 2264 }
2261 2265 } else {
2262 2266 /* Full path provided for module */
2263 2267 char *isa;
2264 2268
2265 2269 /* Check for Instruction Set Architecture indicator */
2266 2270 if ((isa = strstr(arg, PAM_ISA)) != NULL) {
2267 2271 size_t len;
2268 2272 len = strlen(arg) - (sizeof (PAM_ISA)-1) +
2269 2273 sizeof (PAM_ISA_DIR);
2270 2274
2271 2275 /* substitute the architecture dependent path */
2272 2276 if (((*pam)->module_path = malloc(len)) == NULL) {
2273 2277 __pam_log(LOG_AUTH | LOG_ERR,
2274 2278 "strdup: out of memory");
2275 2279 goto out;
2276 2280 }
2277 2281 *isa = '\000';
2278 2282 isa += strlen(PAM_ISA);
2279 2283 (void) snprintf((*pam)->module_path, len, "%s%s%s",
2280 2284 arg, PAM_ISA_DIR, isa);
2281 2285 } else if (((*pam)->module_path = strdup(arg)) == 0) {
2282 2286 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2283 2287 goto out;
2284 2288 }
2285 2289 }
2286 2290
2287 2291 /* count the number of module-specific options first */
2288 2292 argc = 0;
2289 2293 if ((tmp = strdup(cp)) == NULL) {
2290 2294 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2291 2295 goto out;
2292 2296 }
2293 2297 tmp_free = tmp;
2294 2298 for (arg = read_next_token(&tmp); arg; arg = read_next_token(&tmp))
2295 2299 argc++;
2296 2300 free(tmp_free);
2297 2301
2298 2302 /* allocate array for the module-specific options */
2299 2303 if (argc > 0) {
2300 2304 if (((*pam)->module_argv =
2301 2305 calloc(argc+1, sizeof (char *))) == 0) {
2302 2306 __pam_log(LOG_AUTH | LOG_ERR, "calloc: out of memory");
2303 2307 goto out;
2304 2308 }
2305 2309 i = 0;
2306 2310 for (arg = read_next_token(&cp); arg;
2307 2311 arg = read_next_token(&cp)) {
2308 2312 (*pam)->module_argv[i] = strdup(arg);
2309 2313 if ((*pam)->module_argv[i] == NULL) {
2310 2314 __pam_log(LOG_AUTH | LOG_ERR, "strdup failed");
2311 2315 goto out;
2312 2316 }
2313 2317 i++;
2314 2318 }
2315 2319 (*pam)->module_argv[argc] = NULL;
2316 2320 }
2317 2321 (*pam)->module_argc = argc;
2318 2322
2319 2323 error = PAM_SUCCESS; /* success */
2320 2324 (*pam)->pam_err = err; /* was the line truncated */
2321 2325
2322 2326 out:
2323 2327 if (current_line)
2324 2328 free(current_line);
2325 2329 if (error != PAM_SUCCESS) {
2326 2330 /* on error free this */
2327 2331 if (*pam)
2328 2332 free_pamconf(*pam);
2329 2333 }
2330 2334 return (error);
2331 2335 }
2332 2336
2333 2337
2334 2338 /*
2335 2339 * read_next_token - skip tab and space characters and return the next token
2336 2340 */
2337 2341
2338 2342 static char *
2339 2343 read_next_token(char **cpp)
2340 2344 {
2341 2345 register char *cp = *cpp;
2342 2346 char *start;
2343 2347
2344 2348 if (cp == (char *)0) {
2345 2349 *cpp = (char *)0;
2346 2350 return ((char *)0);
2347 2351 }
2348 2352 while (*cp == ' ' || *cp == '\t')
2349 2353 cp++;
2350 2354 if (*cp == '\0') {
2351 2355 *cpp = (char *)0;
2352 2356 return ((char *)0);
2353 2357 }
2354 2358 start = cp;
2355 2359 while (*cp && *cp != ' ' && *cp != '\t')
2356 2360 cp++;
2357 2361 if (*cp != '\0')
2358 2362 *cp++ = '\0';
2359 2363 *cpp = cp;
2360 2364 return (start);
2361 2365 }
2362 2366
2363 2367 static char *
2364 2368 pam_conf_strnchr(char *sp, int c, intptr_t count)
2365 2369 {
2366 2370 while (count) {
2367 2371 if (*sp == (char)c)
2368 2372 return ((char *)sp);
2369 2373 else {
2370 2374 sp++;
2371 2375 count--;
2372 2376 }
2373 2377 };
2374 2378 return (NULL);
2375 2379 }
2376 2380
2377 2381 /*
2378 2382 * nextline - skip all blank lines and comments
2379 2383 */
2380 2384
2381 2385 static char *
2382 2386 nextline(struct pam_fh *pam_fh, pam_handle_t *pamh, int *err)
2383 2387 {
2384 2388 char *ll;
2385 2389 int find_a_line = 0;
2386 2390 char *data = pam_fh->data;
2387 2391 char *bufferp = pam_fh->bufferp;
2388 2392 char *bufferendp = &data[pam_fh->bufsize];
2389 2393 size_t input_len;
2390 2394
2391 2395 /*
2392 2396 * Skip the blank line, comment line
2393 2397 */
2394 2398 while (!find_a_line) {
2395 2399 /* if we are at the end of the buffer, there is no next line */
2396 2400 if (bufferp == bufferendp)
2397 2401 return (NULL);
2398 2402
2399 2403 /* skip blank line */
2400 2404 while (*bufferp == '\n') {
2401 2405 /*
2402 2406 * If we are at the end of the buffer, there is
2403 2407 * no next line.
2404 2408 */
2405 2409 if (++bufferp == bufferendp) {
2406 2410 return (NULL);
2407 2411 }
2408 2412 /* else we check *bufferp again */
2409 2413 }
2410 2414
2411 2415 /* skip comment line */
2412 2416 while (*bufferp == '#') {
2413 2417 if ((ll = pam_conf_strnchr(bufferp, '\n',
2414 2418 bufferendp - bufferp)) != NULL) {
2415 2419 bufferp = ll;
2416 2420 } else {
2417 2421 /*
2418 2422 * this comment line the last line.
2419 2423 * no next line
2420 2424 */
2421 2425 return (NULL);
2422 2426 }
2423 2427
2424 2428 /*
2425 2429 * If we are at the end of the buffer, there is
2426 2430 * no next line.
2427 2431 */
2428 2432 if (bufferp == bufferendp) {
2429 2433 return (NULL);
2430 2434 }
2431 2435 }
2432 2436
2433 2437 if ((*bufferp != '\n') && (*bufferp != '#')) {
2434 2438 find_a_line = 1;
2435 2439 }
2436 2440 }
2437 2441
2438 2442 *err = PAM_SUCCESS;
2439 2443 /* now we find one line */
2440 2444 if ((ll = pam_conf_strnchr(bufferp, '\n', bufferendp - bufferp))
2441 2445 != NULL) {
2442 2446 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) {
2443 2447 __pam_log(LOG_AUTH | LOG_ERR,
2444 2448 "nextline[%d:%s]: pam.conf line too long %.256s",
2445 2449 pamh->include_depth, pam_trace_cname(pamh),
2446 2450 bufferp);
2447 2451 input_len = sizeof (pam_fh->line) - 1;
2448 2452 *err = PAM_SERVICE_ERR;
2449 2453 }
2450 2454 (void) strncpy(pam_fh->line, bufferp, input_len);
2451 2455 pam_fh->line[input_len] = '\0';
2452 2456 pam_fh->bufferp = ll++;
2453 2457 } else {
2454 2458 ll = bufferendp;
2455 2459 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) {
2456 2460 __pam_log(LOG_AUTH | LOG_ERR,
2457 2461 "nextline[%d:%s]: pam.conf line too long %.256s",
2458 2462 pamh->include_depth, pam_trace_cname(pamh),
2459 2463 bufferp);
2460 2464 input_len = sizeof (pam_fh->line) - 1;
2461 2465 *err = PAM_SERVICE_ERR;
2462 2466 }
2463 2467 (void) strncpy(pam_fh->line, bufferp, input_len);
2464 2468 pam_fh->line[input_len] = '\0';
2465 2469 pam_fh->bufferp = ll;
2466 2470 }
2467 2471
2468 2472 return (pam_fh->line);
2469 2473 }
2470 2474
2471 2475 /*
2472 2476 * verify_pam_conf - verify that the pam_conf entry is filled in.
2473 2477 *
2474 2478 * True = Error if there is no service.
2475 2479 * True = Error if there is a service and it matches the requested service
2476 2480 * but, the type, flag, line overflow, or path is in error.
2477 2481 */
2478 2482
2479 2483 static int
2480 2484 verify_pam_conf(pamtab_t *pam, char *service)
2481 2485 {
2482 2486 return ((pam->pam_service == (char *)NULL) ||
2483 2487 ((strcasecmp(pam->pam_service, service) == 0) &&
2484 2488 ((pam->pam_type == -1) ||
2485 2489 (pam->pam_flag == 0) ||
2486 2490 (pam->pam_err != PAM_SUCCESS) ||
2487 2491 (pam->module_path == (char *)NULL))));
2488 2492 }
2489 2493
2490 2494 /*
2491 2495 * Routines to free allocated storage
2492 2496 */
2493 2497
2494 2498 /*
2495 2499 * clean_up - free allocated storage in the pam handle
2496 2500 */
2497 2501
2498 2502 static void
2499 2503 clean_up(pam_handle_t *pamh)
2500 2504 {
2501 2505 int i;
2502 2506 pam_repository_t *auth_rep;
2503 2507
2504 2508 if (pamh) {
2505 2509 while (pamh->include_depth >= 0) {
2506 2510 free_pam_conf_info(pamh);
2507 2511 pamh->include_depth--;
2508 2512 }
2509 2513
2510 2514 /* Cleanup PAM_REPOSITORY structure */
2511 2515 auth_rep = pamh->ps_item[PAM_REPOSITORY].pi_addr;
2512 2516 if (auth_rep != NULL) {
2513 2517 if (auth_rep->type != NULL)
2514 2518 free(auth_rep->type);
2515 2519 if (auth_rep->scope != NULL)
2516 2520 free(auth_rep->scope);
2517 2521 }
2518 2522
2519 2523 for (i = 0; i < PAM_MAX_ITEMS; i++) {
2520 2524 if (pamh->ps_item[i].pi_addr != NULL) {
2521 2525 if (i == PAM_AUTHTOK || i == PAM_OLDAUTHTOK) {
2522 2526 (void) memset(pamh->ps_item[i].pi_addr,
2523 2527 0, pamh->ps_item[i].pi_size);
2524 2528 }
2525 2529 free(pamh->ps_item[i].pi_addr);
2526 2530 }
2527 2531 }
2528 2532 free(pamh);
2529 2533 }
2530 2534 }
2531 2535
2532 2536 /*
2533 2537 * free_pamconf - free memory used to store pam.conf entry
2534 2538 */
2535 2539
2536 2540 static void
2537 2541 free_pamconf(pamtab_t *cp)
2538 2542 {
2539 2543 int i;
2540 2544
2541 2545 if (cp) {
2542 2546 if (cp->pam_service)
2543 2547 free(cp->pam_service);
2544 2548 if (cp->module_path)
2545 2549 free(cp->module_path);
2546 2550 for (i = 0; i < cp->module_argc; i++) {
2547 2551 if (cp->module_argv[i])
2548 2552 free(cp->module_argv[i]);
2549 2553 }
2550 2554 if (cp->module_argc > 0)
2551 2555 free(cp->module_argv);
2552 2556 if (cp->function_ptr)
2553 2557 free(cp->function_ptr);
2554 2558
2555 2559 free(cp);
2556 2560 }
2557 2561 }
2558 2562
2559 2563 /*
2560 2564 * free_pam_conf_info - free memory used to store all pam.conf info
2561 2565 * under the pam handle
2562 2566 */
2563 2567
2564 2568 static void
2565 2569 free_pam_conf_info(pam_handle_t *pamh)
2566 2570 {
2567 2571 pamtab_t *pamentp;
2568 2572 pamtab_t *pament_trail;
2569 2573 int i = pamh->include_depth;
2570 2574 int j;
2571 2575
2572 2576 for (j = 0; j < PAM_NUM_MODULE_TYPES; j++) {
2573 2577 pamentp = pamh->pam_conf_info[i][j];
2574 2578 pamh->pam_conf_info[i][j] = NULL;
2575 2579 pament_trail = pamentp;
2576 2580 while (pamentp) {
2577 2581 pamentp = pamentp->next;
2578 2582 free_pamconf(pament_trail);
2579 2583 pament_trail = pamentp;
2580 2584 }
2581 2585 }
2582 2586 if (pamh->pam_conf_name[i] != NULL) {
2583 2587 free(pamh->pam_conf_name[i]);
2584 2588 pamh->pam_conf_name[i] = NULL;
2585 2589 }
2586 2590 }
2587 2591
2588 2592 static void
2589 2593 free_env(env_list *pam_env)
2590 2594 {
2591 2595 if (pam_env) {
2592 2596 if (pam_env->name)
2593 2597 free(pam_env->name);
2594 2598 if (pam_env->value)
2595 2599 free(pam_env->value);
2596 2600 free(pam_env);
2597 2601 }
2598 2602 }
2599 2603
2600 2604 /*
2601 2605 * Internal convenience functions for Solaris PAM service modules.
2602 2606 */
2603 2607
2604 2608 #include <libintl.h>
2605 2609 #include <nl_types.h>
2606 2610 #include <synch.h>
2607 2611 #include <locale.h>
2608 2612 #include <thread.h>
2609 2613
2610 2614 typedef struct pam_msg_data {
2611 2615 nl_catd fd;
2612 2616 } pam_msg_data_t;
2613 2617
2614 2618 /*
2615 2619 * free_resp():
2616 2620 * free storage for responses used in the call back "pam_conv" functions
2617 2621 */
2618 2622
2619 2623 void
2620 2624 free_resp(int num_msg, struct pam_response *resp)
2621 2625 {
2622 2626 int i;
2623 2627 struct pam_response *r;
2624 2628
2625 2629 if (resp) {
2626 2630 r = resp;
2627 2631 for (i = 0; i < num_msg; i++, r++) {
2628 2632 if (r->resp) {
2629 2633 /* clear before freeing -- may be a password */
2630 2634 bzero(r->resp, strlen(r->resp));
2631 2635 free(r->resp);
2632 2636 r->resp = NULL;
2633 2637 }
2634 2638 }
2635 2639 free(resp);
2636 2640 }
2637 2641 }
2638 2642
2639 2643 static int
2640 2644 do_conv(pam_handle_t *pamh, int msg_style, int num_msg,
2641 2645 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp,
2642 2646 struct pam_response *ret_respp[])
2643 2647 {
2644 2648 struct pam_message *msg;
2645 2649 struct pam_message *m;
2646 2650 int i;
2647 2651 int k;
2648 2652 int retcode;
2649 2653 struct pam_conv *pam_convp;
2650 2654
2651 2655 if ((retcode = pam_get_item(pamh, PAM_CONV,
2652 2656 (void **)&pam_convp)) != PAM_SUCCESS) {
2653 2657 return (retcode);
2654 2658 }
2655 2659
2656 2660 /*
2657 2661 * When pam_set_item() is called to set PAM_CONV and the
2658 2662 * item is NULL, memset(pip->pi_addr, 0, size) is called.
2659 2663 * So at this point, we should check whether pam_convp->conv
2660 2664 * is NULL or not.
2661 2665 */
2662 2666 if ((pam_convp == NULL) || (pam_convp->conv == NULL))
2663 2667 return (PAM_SYSTEM_ERR);
2664 2668
2665 2669 i = 0;
2666 2670 k = num_msg;
2667 2671
2668 2672 msg = calloc(num_msg, sizeof (struct pam_message));
2669 2673 if (msg == NULL) {
2670 2674 return (PAM_BUF_ERR);
2671 2675 }
2672 2676 m = msg;
2673 2677
2674 2678 while (k--) {
2675 2679 /*
2676 2680 * fill out the message structure to display prompt message
2677 2681 */
2678 2682 m->msg_style = msg_style;
2679 2683 m->msg = messages[i];
2680 2684 pam_trace(PAM_DEBUG_CONV,
2681 2685 "pam_conv_msg(%p:%d[%d]=%s)",
2682 2686 (void *)pamh, msg_style, i, messages[i]);
2683 2687 m++;
2684 2688 i++;
2685 2689 }
2686 2690
2687 2691 /*
2688 2692 * The UNIX pam modules always calls __pam_get_authtok() and
2689 2693 * __pam_display_msg() with a NULL pointer as the conv_apdp.
2690 2694 * In case the conv_apdp is NULL and the pam_convp->appdata_ptr
2691 2695 * is not NULL, we should pass the pam_convp->appdata_ptr
2692 2696 * to the conversation function.
2693 2697 */
2694 2698 if (conv_apdp == NULL && pam_convp->appdata_ptr != NULL)
2695 2699 conv_apdp = pam_convp->appdata_ptr;
2696 2700
2697 2701 /*
2698 2702 * Call conv function to display the prompt.
2699 2703 */
2700 2704 retcode = (pam_convp->conv)(num_msg, &msg, ret_respp, conv_apdp);
2701 2705 pam_trace(PAM_DEBUG_CONV,
2702 2706 "pam_conv_resp(%p pam_conv = %s) ret_respp = %p",
2703 2707 (void *)pamh, pam_strerror(pamh, retcode), (void *)ret_respp);
2704 2708 if (*ret_respp == NULL) {
2705 2709 pam_trace(PAM_DEBUG_CONV,
2706 2710 "pam_conv_resp(%p No response requested)", (void *)pamh);
2707 2711 } else if ((pam_debug & (PAM_DEBUG_CONV | PAM_DEBUG_AUTHTOK)) != 0) {
2708 2712 struct pam_response *r = *ret_respp;
2709 2713
2710 2714 for (i = 0; i < num_msg; i++, r++) {
2711 2715 if (r->resp == NULL) {
2712 2716 pam_trace(PAM_DEBUG_CONV,
2713 2717 "pam_conv_resp(%p:"
2714 2718 "[%d] NULL response string)",
2715 2719 (void *)pamh, i);
2716 2720 } else {
2717 2721 if (msg_style == PAM_PROMPT_ECHO_OFF) {
2718 2722 #ifdef DEBUG
2719 2723 pam_trace(PAM_DEBUG_AUTHTOK,
2720 2724 "pam_conv_resp(%p:[%d]=%s, "
2721 2725 "code=%d)",
2722 2726 (void *)pamh, i, r->resp,
2723 2727 r->resp_retcode);
2724 2728 #endif /* DEBUG */
2725 2729 pam_trace(PAM_DEBUG_CONV,
2726 2730 "pam_conv_resp(%p:[%d] len=%lu, "
2727 2731 "code=%d)",
2728 2732 (void *)pamh, i,
2729 2733 (ulong_t)strlen(r->resp),
2730 2734 r->resp_retcode);
2731 2735 } else {
2732 2736 pam_trace(PAM_DEBUG_CONV,
2733 2737 "pam_conv_resp(%p:[%d]=%s, "
2734 2738 "code=%d)",
2735 2739 (void *)pamh, i, r->resp,
2736 2740 r->resp_retcode);
2737 2741 }
2738 2742 }
2739 2743 }
2740 2744 }
2741 2745
2742 2746 if (msg)
2743 2747 free(msg);
2744 2748 return (retcode);
2745 2749 }
2746 2750
2747 2751 /*
2748 2752 * __pam_display_msg():
2749 2753 * display message by calling the call back functions
2750 2754 * provided by the application through "pam_conv" structure
2751 2755 */
2752 2756
2753 2757 int
2754 2758 __pam_display_msg(pam_handle_t *pamh, int msg_style, int num_msg,
2755 2759 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp)
2756 2760 {
2757 2761 struct pam_response *ret_respp = NULL;
2758 2762 int ret;
2759 2763
2760 2764 ret = do_conv(pamh, msg_style, num_msg, messages,
2761 2765 conv_apdp, &ret_respp);
2762 2766
2763 2767 if (ret_respp != NULL)
2764 2768 free_resp(num_msg, ret_respp);
2765 2769
2766 2770 return (ret);
2767 2771 }
2768 2772
2769 2773 /*
2770 2774 * __pam_get_authtok()
2771 2775 * retrieves a password of at most PASS_MAX length from the pam
2772 2776 * handle (pam_get_item) or from the input stream (do_conv).
2773 2777 *
2774 2778 * This function allocates memory for the new authtok.
2775 2779 * Applications calling this function are responsible for
2776 2780 * freeing this memory.
2777 2781 *
2778 2782 * If "source" is
2779 2783 * PAM_HANDLE
2780 2784 * and "type" is:
2781 2785 * PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK)
2782 2786 * PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK)
2783 2787 *
2784 2788 * If "source" is
2785 2789 * PAM_PROMPT
2786 2790 * and "type" is:
2787 2791 * 0: Prompt for new passwd, do not even attempt
2788 2792 * to store it in the pam handle.
2789 2793 * PAM_AUTHTOK: Prompt for new passwd, store in pam handle as
2790 2794 * PAM_AUTHTOK item if this value is not already set.
2791 2795 * PAM_OLDAUTHTOK: Prompt for new passwd, store in pam handle as
2792 2796 * PAM_OLDAUTHTOK item if this value is not
2793 2797 * already set.
2794 2798 */
2795 2799 int
2796 2800 __pam_get_authtok(pam_handle_t *pamh, int source, int type, char *prompt,
2797 2801 char **authtok)
2798 2802 {
2799 2803 int error = PAM_SYSTEM_ERR;
2800 2804 char *new_password = NULL;
2801 2805 struct pam_response *ret_resp = NULL;
2802 2806 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
2803 2807
2804 2808 if ((*authtok = calloc(PASS_MAX+1, sizeof (char))) == NULL)
2805 2809 return (PAM_BUF_ERR);
2806 2810
2807 2811 if (prompt == NULL)
2808 2812 prompt = dgettext(TEXT_DOMAIN, "password: ");
2809 2813
2810 2814 switch (source) {
2811 2815 case PAM_HANDLE:
2812 2816
2813 2817 /* get password from pam handle item list */
2814 2818
2815 2819 switch (type) {
2816 2820 case PAM_AUTHTOK:
2817 2821 case PAM_OLDAUTHTOK:
2818 2822
2819 2823 if ((error = pam_get_item(pamh, type,
2820 2824 (void **)&new_password)) != PAM_SUCCESS)
2821 2825 goto err_ret;
2822 2826
2823 2827 if (new_password == NULL || new_password[0] == '\0') {
2824 2828 free(*authtok);
2825 2829 *authtok = NULL;
2826 2830 } else {
2827 2831 (void) strlcpy(*authtok, new_password,
2828 2832 PASS_MAX+1);
2829 2833 }
2830 2834 break;
2831 2835 default:
2832 2836 __pam_log(LOG_AUTH | LOG_ERR,
2833 2837 "__pam_get_authtok() invalid type: %d", type);
2834 2838 error = PAM_SYMBOL_ERR;
2835 2839 goto err_ret;
2836 2840 }
2837 2841 break;
2838 2842 case PAM_PROMPT:
2839 2843
2840 2844 /*
2841 2845 * Prompt for new password and save in pam handle item list
2842 2846 * if the that item is not already set.
2843 2847 */
2844 2848
2845 2849 (void) strncpy(messages[0], prompt, sizeof (messages[0]));
2846 2850 if ((error = do_conv(pamh, PAM_PROMPT_ECHO_OFF, 1, messages,
2847 2851 NULL, &ret_resp)) != PAM_SUCCESS)
2848 2852 goto err_ret;
2849 2853
2850 2854 if (ret_resp->resp == NULL) {
2851 2855 /* getpass didn't return anything */
2852 2856 error = PAM_SYSTEM_ERR;
2853 2857 goto err_ret;
2854 2858 }
2855 2859
2856 2860 /* save the new password if this item was NULL */
2857 2861 if (type) {
2858 2862 if ((error = pam_get_item(pamh, type,
2859 2863 (void **)&new_password)) != PAM_SUCCESS) {
2860 2864 free_resp(1, ret_resp);
2861 2865 goto err_ret;
2862 2866 }
2863 2867 if (new_password == NULL)
2864 2868 (void) pam_set_item(pamh, type, ret_resp->resp);
2865 2869 }
2866 2870
2867 2871 (void) strlcpy(*authtok, ret_resp->resp, PASS_MAX+1);
2868 2872 free_resp(1, ret_resp);
2869 2873 break;
2870 2874 default:
2871 2875 __pam_log(LOG_AUTH | LOG_ERR,
2872 2876 "__pam_get_authtok() invalid source: %d", source);
2873 2877 error = PAM_SYMBOL_ERR;
2874 2878 goto err_ret;
2875 2879 }
2876 2880
2877 2881 return (PAM_SUCCESS);
2878 2882
2879 2883 err_ret:
2880 2884 bzero(*authtok, PASS_MAX+1);
2881 2885 free(*authtok);
2882 2886 *authtok = NULL;
2883 2887 return (error);
2884 2888 }
↓ open down ↓ |
2073 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX