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