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 2020, 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 *
pam_trace_iname(int item_type,char * iname_buf)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 *
pam_trace_fname(int flag)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 *
pam_trace_cname(pam_handle_t * pamh)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
pam_settrace()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
pam_trace(int flag,char * format,...)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
__pam_log(int priority,const char * format,...)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
pam_start(const char * service,const char * user,const struct pam_conv * pam_conv,pam_handle_t ** pamh)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
pam_end(pam_handle_t * pamh,int pam_status)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
pam_set_item(pam_handle_t * pamh,int item_type,const void * item)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
pam_get_item(const pam_handle_t * pamh,int item_type,void ** item)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
parse_user_name(char * user_input,char ** ret_username)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 (index >= PAM_MAX_RESP_SIZE)) {
661 break;
662 } else {
663 username[index] = *ptr;
664 index++;
665 ptr++;
666 }
667 }
668
669 /* ret_username will be freed in pam_get_user(). */
670 if (index >= PAM_MAX_RESP_SIZE ||
671 (*ret_username = strdup(username)) == NULL)
672 return (PAM_BUF_ERR);
673 return (PAM_SUCCESS);
674 }
675
676 /*
677 * Get the value of PAM_USER. If not set, then use the convenience function
678 * to prompt for the user. Use prompt if specified, else use PAM_USER_PROMPT
679 * if it is set, else use default.
680 */
681 #define WHITESPACE 0
682 #define USERNAME 1
683
684 int
pam_get_user(pam_handle_t * pamh,char ** user,const char * prompt_override)685 pam_get_user(pam_handle_t *pamh, char **user, const char *prompt_override)
686 {
687 int status;
688 char *prompt = NULL;
689 char *real_username;
690 struct pam_response *ret_resp = NULL;
691 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
692
693 pam_trace(PAM_DEBUG_DEFAULT,
694 "pam_get_user(%p, %p, %s)", (void *)pamh, (void *)*user,
695 prompt_override ? prompt_override : "NULL");
696 if (pamh == NULL)
697 return (PAM_SYSTEM_ERR);
698
699 if ((status = pam_get_item(pamh, PAM_USER, (void **)user))
700 != PAM_SUCCESS) {
701 return (status);
702 }
703
704 /* if the user is set, return it */
705
706 if (*user != NULL && *user[0] != '\0') {
707 return (PAM_SUCCESS);
708 }
709
710 /*
711 * if the module is requesting a special prompt, use it.
712 * else use PAM_USER_PROMPT.
713 */
714
715 if (prompt_override != NULL) {
716 prompt = (char *)prompt_override;
717 } else {
718 status = pam_get_item(pamh, PAM_USER_PROMPT, (void**)&prompt);
719 if (status != PAM_SUCCESS) {
720 return (status);
721 }
722 }
723
724 /* if the prompt is not set, use default */
725
726 if (prompt == NULL || prompt[0] == '\0') {
727 prompt = dgettext(TEXT_DOMAIN, "Please enter user name: ");
728 }
729
730 /* prompt for the user */
731
732 (void) strncpy(messages[0], prompt, sizeof (messages[0]));
733
734 for (;;) {
735 int state = WHITESPACE;
736
737 status = do_conv(pamh, PAM_PROMPT_ECHO_ON, 1, messages,
738 NULL, &ret_resp);
739
740 if (status != PAM_SUCCESS) {
741 return (status);
742 }
743
744 if (ret_resp->resp && ret_resp->resp[0] != '\0') {
745 int len = strlen(ret_resp->resp);
746 int i;
747
748 for (i = 0; i < len; i++) {
749 if ((ret_resp->resp[i] != ' ') &&
750 (ret_resp->resp[i] != '\t')) {
751 state = USERNAME;
752 break;
753 }
754 }
755
756 if (state == USERNAME)
757 break;
758 }
759 /* essentially empty response, try again */
760 free_resp(1, ret_resp);
761 ret_resp = NULL;
762 }
763
764 /* set PAM_USER */
765 /* Parse the user input to get the user name. */
766 status = parse_user_name(ret_resp->resp, &real_username);
767
768 if (status != PAM_SUCCESS) {
769 if (real_username != NULL)
770 free(real_username);
771 free_resp(1, ret_resp);
772 return (status);
773 }
774
775 status = pam_set_item(pamh, PAM_USER, real_username);
776
777 free(real_username);
778
779 free_resp(1, ret_resp);
780 if (status != PAM_SUCCESS) {
781 return (status);
782 }
783
784 /*
785 * finally, get PAM_USER. We have to call pam_get_item to get
786 * the value of user because pam_set_item mallocs the memory.
787 */
788
789 status = pam_get_item(pamh, PAM_USER, (void**)user);
790 return (status);
791 }
792
793 /*
794 * Set module specific data
795 */
796
797 int
pam_set_data(pam_handle_t * pamh,const char * module_data_name,void * data,void (* cleanup)(pam_handle_t * pamh,void * data,int pam_end_status))798 pam_set_data(pam_handle_t *pamh, const char *module_data_name, void *data,
799 void (*cleanup)(pam_handle_t *pamh, void *data, int pam_end_status))
800 {
801 struct pam_module_data *psd;
802
803 pam_trace(PAM_DEBUG_DATA,
804 "pam_set_data(%p:%s:%d)=%p", (void *)pamh,
805 (module_data_name != NULL) ? module_data_name : "NULL",
806 (pamh != NULL) ? pamh->pam_inmodule : -1, data);
807 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) ||
808 module_data_name == NULL) {
809 return (PAM_SYSTEM_ERR);
810 }
811
812 /* check if module data already exists */
813
814 for (psd = pamh->ssd; psd; psd = psd->next) {
815 if (strcmp(psd->module_data_name, module_data_name) == 0) {
816 /* clean up original data before setting the new data */
817 if (psd->cleanup) {
818 psd->cleanup(pamh, psd->data, PAM_SUCCESS);
819 }
820 psd->data = (void *)data;
821 psd->cleanup = cleanup;
822 return (PAM_SUCCESS);
823 }
824 }
825
826 psd = malloc(sizeof (struct pam_module_data));
827 if (psd == NULL)
828 return (PAM_BUF_ERR);
829
830 psd->module_data_name = strdup(module_data_name);
831 if (psd->module_data_name == NULL) {
832 free(psd);
833 return (PAM_BUF_ERR);
834 }
835
836 psd->data = (void *)data;
837 psd->cleanup = cleanup;
838 psd->next = pamh->ssd;
839 pamh->ssd = psd;
840 return (PAM_SUCCESS);
841 }
842
843 /*
844 * get module specific data
845 */
846
847 int
pam_get_data(const pam_handle_t * pamh,const char * module_data_name,const void ** data)848 pam_get_data(const pam_handle_t *pamh, const char *module_data_name,
849 const void **data)
850 {
851 struct pam_module_data *psd;
852
853 if (pamh == NULL || (pamh->pam_inmodule != WO_OK) ||
854 module_data_name == NULL) {
855 pam_trace(PAM_DEBUG_DATA,
856 "pam_get_data(%p:%s:%d)=%p", (void *)pamh,
857 module_data_name ? module_data_name : "NULL",
858 pamh->pam_inmodule, *data);
859 return (PAM_SYSTEM_ERR);
860 }
861
862 for (psd = pamh->ssd; psd; psd = psd->next) {
863 if (strcmp(psd->module_data_name, module_data_name) == 0) {
864 *data = psd->data;
865 pam_trace(PAM_DEBUG_DATA,
866 "pam_get_data(%p:%s)=%p", (void *)pamh,
867 module_data_name, *data);
868 return (PAM_SUCCESS);
869 }
870 }
871 pam_trace(PAM_DEBUG_DATA,
872 "pam_get_data(%p:%s)=%s", (void *)pamh, module_data_name,
873 "PAM_NO_MODULE_DATA");
874
875 return (PAM_NO_MODULE_DATA);
876 }
877
878 /*
879 * PAM equivalent to strerror()
880 */
881 /* ARGSUSED */
882 const char *
pam_strerror(pam_handle_t * pamh,int errnum)883 pam_strerror(pam_handle_t *pamh, int errnum)
884 {
885 switch (errnum) {
886 case PAM_SUCCESS:
887 return (dgettext(TEXT_DOMAIN, "Success"));
888 case PAM_OPEN_ERR:
889 return (dgettext(TEXT_DOMAIN, "Dlopen failure"));
890 case PAM_SYMBOL_ERR:
891 return (dgettext(TEXT_DOMAIN, "Symbol not found"));
892 case PAM_SERVICE_ERR:
893 return (dgettext(TEXT_DOMAIN,
894 "Error in underlying service module"));
895 case PAM_SYSTEM_ERR:
896 return (dgettext(TEXT_DOMAIN, "System error"));
897 case PAM_BUF_ERR:
898 return (dgettext(TEXT_DOMAIN, "Memory buffer error"));
899 case PAM_CONV_ERR:
900 return (dgettext(TEXT_DOMAIN, "Conversation failure"));
901 case PAM_PERM_DENIED:
902 return (dgettext(TEXT_DOMAIN, "Permission denied"));
903 case PAM_MAXTRIES:
904 return (dgettext(TEXT_DOMAIN,
905 "Maximum number of attempts exceeded"));
906 case PAM_AUTH_ERR:
907 return (dgettext(TEXT_DOMAIN, "Authentication failed"));
908 case PAM_NEW_AUTHTOK_REQD:
909 return (dgettext(TEXT_DOMAIN, "Get new authentication token"));
910 case PAM_CRED_INSUFFICIENT:
911 return (dgettext(TEXT_DOMAIN, "Insufficient credentials"));
912 case PAM_AUTHINFO_UNAVAIL:
913 return (dgettext(TEXT_DOMAIN,
914 "Can not retrieve authentication info"));
915 case PAM_USER_UNKNOWN:
916 return (dgettext(TEXT_DOMAIN, "No account present for user"));
917 case PAM_CRED_UNAVAIL:
918 return (dgettext(TEXT_DOMAIN,
919 "Can not retrieve user credentials"));
920 case PAM_CRED_EXPIRED:
921 return (dgettext(TEXT_DOMAIN,
922 "User credentials have expired"));
923 case PAM_CRED_ERR:
924 return (dgettext(TEXT_DOMAIN,
925 "Failure setting user credentials"));
926 case PAM_ACCT_EXPIRED:
927 return (dgettext(TEXT_DOMAIN, "User account has expired"));
928 case PAM_AUTHTOK_EXPIRED:
929 return (dgettext(TEXT_DOMAIN, "User password has expired"));
930 case PAM_SESSION_ERR:
931 return (dgettext(TEXT_DOMAIN,
932 "Can not make/remove entry for session"));
933 case PAM_AUTHTOK_ERR:
934 return (dgettext(TEXT_DOMAIN,
935 "Authentication token manipulation error"));
936 case PAM_AUTHTOK_RECOVERY_ERR:
937 return (dgettext(TEXT_DOMAIN,
938 "Authentication token can not be recovered"));
939 case PAM_AUTHTOK_LOCK_BUSY:
940 return (dgettext(TEXT_DOMAIN,
941 "Authentication token lock busy"));
942 case PAM_AUTHTOK_DISABLE_AGING:
943 return (dgettext(TEXT_DOMAIN,
944 "Authentication token aging disabled"));
945 case PAM_NO_MODULE_DATA:
946 return (dgettext(TEXT_DOMAIN,
947 "Module specific data not found"));
948 case PAM_IGNORE:
949 return (dgettext(TEXT_DOMAIN, "Ignore module"));
950 case PAM_ABORT:
951 return (dgettext(TEXT_DOMAIN, "General PAM failure "));
952 case PAM_TRY_AGAIN:
953 return (dgettext(TEXT_DOMAIN,
954 "Unable to complete operation. Try again"));
955 default:
956 return (dgettext(TEXT_DOMAIN, "Unknown error"));
957 }
958 }
959
960 static void *
sm_name(int ind)961 sm_name(int ind)
962 {
963 switch (ind) {
964 case PAM_AUTHENTICATE:
965 return (PAM_SM_AUTHENTICATE);
966 case PAM_SETCRED:
967 return (PAM_SM_SETCRED);
968 case PAM_ACCT_MGMT:
969 return (PAM_SM_ACCT_MGMT);
970 case PAM_OPEN_SESSION:
971 return (PAM_SM_OPEN_SESSION);
972 case PAM_CLOSE_SESSION:
973 return (PAM_SM_CLOSE_SESSION);
974 case PAM_CHAUTHTOK:
975 return (PAM_SM_CHAUTHTOK);
976 }
977 return (NULL);
978 }
979
980 static int
func(pamtab_t * modulep,int ind)981 (*func(pamtab_t *modulep, int ind))()
982 {
983 void *funcp;
984
985 if ((funcp = modulep->function_ptr) == NULL)
986 return (NULL);
987
988 switch (ind) {
989 case PAM_AUTHENTICATE:
990 return (((struct auth_module *)funcp)->pam_sm_authenticate);
991 case PAM_SETCRED:
992 return (((struct auth_module *)funcp)->pam_sm_setcred);
993 case PAM_ACCT_MGMT:
994 return (((struct account_module *)funcp)->pam_sm_acct_mgmt);
995 case PAM_OPEN_SESSION:
996 return (((struct session_module *)funcp)->pam_sm_open_session);
997 case PAM_CLOSE_SESSION:
998 return (((struct session_module *)funcp)->pam_sm_close_session);
999 case PAM_CHAUTHTOK:
1000 return (((struct password_module *)funcp)->pam_sm_chauthtok);
1001 }
1002 return (NULL);
1003 }
1004
1005 /*
1006 * Run through the PAM service module stack for the given module type.
1007 */
1008 static int
run_stack(pam_handle_t * pamh,int flags,int type,int def_err,int ind,char * function_name)1009 run_stack(pam_handle_t *pamh, int flags, int type, int def_err, int ind,
1010 char *function_name)
1011 {
1012 int err = PAM_SYSTEM_ERR; /* preset */
1013 int optional_error = 0;
1014 int required_error = 0;
1015 int success = 0;
1016 pamtab_t *modulep;
1017 int (*sm_func)();
1018
1019 if (pamh == NULL)
1020 return (PAM_SYSTEM_ERR);
1021
1022 /* read initial entries from pam.conf */
1023 if ((err = read_pam_conf(pamh, PAM_CONFIG)) != PAM_SUCCESS) {
1024 return (err);
1025 }
1026
1027 if ((modulep =
1028 pamh->pam_conf_info[pamh->include_depth][type]) == NULL) {
1029 __pam_log(LOG_AUTH | LOG_ERR, "%s no initial module present",
1030 pam_trace_cname(pamh));
1031 goto exit_return;
1032 }
1033
1034 pamh->pam_inmodule = WO_OK; /* OK to get AUTHTOK */
1035 include:
1036 pam_trace(PAM_DEBUG_MODULE,
1037 "[%d:%s]:run_stack:%s(%p, %x): %s", pamh->include_depth,
1038 pam_trace_cname(pamh), function_name, (void *)pamh, flags,
1039 modulep ? modulep->module_path : "NULL");
1040
1041 while (modulep != NULL) {
1042 if (modulep->pam_flag & PAM_INCLUDE) {
1043 /* save the return location */
1044 pamh->pam_conf_modulep[pamh->include_depth] =
1045 modulep->next;
1046 pam_trace(PAM_DEBUG_MODULE,
1047 "setting for include[%d:%p]",
1048 pamh->include_depth, (void *)modulep->next);
1049 if (pamh->include_depth++ >= PAM_MAX_INCLUDE) {
1050 __pam_log(LOG_AUTH | LOG_ERR,
1051 "run_stack: includes too deep %d "
1052 "found trying to include %s from %s, %d "
1053 "allowed", pamh->include_depth,
1054 modulep->module_path, pamh->pam_conf_name
1055 [PAM_MAX_INCLUDE] == NULL ? "NULL" :
1056 pamh->pam_conf_name[PAM_MAX_INCLUDE],
1057 PAM_MAX_INCLUDE);
1058 goto exit_return;
1059 }
1060 if ((err = read_pam_conf(pamh,
1061 modulep->module_path)) != PAM_SUCCESS) {
1062 __pam_log(LOG_AUTH | LOG_ERR,
1063 "run_stack[%d:%s]: can't read included "
1064 "conf %s", pamh->include_depth,
1065 pam_trace_cname(pamh),
1066 modulep->module_path);
1067 goto exit_return;
1068 }
1069 if ((modulep = pamh->pam_conf_info
1070 [pamh->include_depth][type]) == NULL) {
1071 __pam_log(LOG_AUTH | LOG_ERR,
1072 "run_stack[%d:%s]: no include module "
1073 "present %s", pamh->include_depth,
1074 pam_trace_cname(pamh), function_name);
1075 goto exit_return;
1076 }
1077 if (modulep->pam_flag & PAM_INCLUDE) {
1078 /* first line another include */
1079 goto include;
1080 }
1081 pam_trace(PAM_DEBUG_DEFAULT, "include[%d:%s]"
1082 "(%p, %s)=%s", pamh->include_depth,
1083 pam_trace_cname(pamh), (void *)pamh,
1084 function_name, modulep->module_path);
1085 if ((err = load_modules(pamh, type, sm_name(ind),
1086 pamh->pam_conf_info
1087 [pamh->include_depth][type])) != PAM_SUCCESS) {
1088 pam_trace(PAM_DEBUG_DEFAULT,
1089 "[%d:%s]:%s(%p, %x): load_modules failed",
1090 pamh->include_depth, pam_trace_cname(pamh),
1091 function_name, (void *)pamh, flags);
1092 goto exit_return;
1093 }
1094 if ((modulep = pamh->pam_conf_info
1095 [pamh->include_depth][type]) == NULL) {
1096 __pam_log(LOG_AUTH | LOG_ERR,
1097 "%s no initial module present",
1098 pam_trace_cname(pamh));
1099 goto exit_return;
1100 }
1101 } else if ((err = load_modules(pamh, type, sm_name(ind),
1102 modulep)) != PAM_SUCCESS) {
1103 pam_trace(PAM_DEBUG_DEFAULT,
1104 "[%d:%s]:%s(%p, %x): load_modules failed",
1105 pamh->include_depth, pam_trace_cname(pamh),
1106 function_name, (void *)pamh, flags);
1107 goto exit_return;
1108 } /* PAM_INCLUDE */
1109 sm_func = func(modulep, ind);
1110 if (sm_func) {
1111 err = sm_func(pamh, flags, modulep->module_argc,
1112 (const char **)modulep->module_argv);
1113
1114 pam_trace(PAM_DEBUG_MODULE,
1115 "[%d:%s]:%s(%p, %x): %s returned %s",
1116 pamh->include_depth, pam_trace_cname(pamh),
1117 function_name, (void *)pamh, flags,
1118 modulep->module_path, pam_strerror(pamh, err));
1119
1120 switch (err) {
1121 case PAM_IGNORE:
1122 /* do nothing */
1123 break;
1124 case PAM_SUCCESS:
1125 if ((modulep->pam_flag & PAM_SUFFI_BIND) &&
1126 !required_error) {
1127 pamh->pam_inmodule = RW_OK;
1128 pam_trace(PAM_DEBUG_MODULE,
1129 "[%d:%s]:%s(%p, %x): %s: success",
1130 pamh->include_depth,
1131 pam_trace_cname(pamh),
1132 function_name, (void *)pamh, flags,
1133 (modulep->pam_flag & PAM_BINDING) ?
1134 PAM_BINDING_NAME :
1135 PAM_SUFFICIENT_NAME);
1136 goto exit_return;
1137 }
1138 success = 1;
1139 break;
1140 case PAM_TRY_AGAIN:
1141 /*
1142 * We need to return immediately, and
1143 * we shouldn't reset the AUTHTOK item
1144 * since it is not an error per-se.
1145 */
1146 pamh->pam_inmodule = RW_OK;
1147 pam_trace(PAM_DEBUG_MODULE,
1148 "[%d:%s]:%s(%p, %x): TRY_AGAIN: %s",
1149 pamh->include_depth, pam_trace_cname(pamh),
1150 function_name, (void *)pamh, flags,
1151 pam_strerror(pamh, required_error ?
1152 required_error : err));
1153 err = required_error ? required_error : err;
1154 goto exit_return;
1155 default:
1156 if (modulep->pam_flag & PAM_REQUISITE) {
1157 pamh->pam_inmodule = RW_OK;
1158 pam_trace(PAM_DEBUG_MODULE,
1159 "[%d:%s]:%s(%p, %x): requisite: %s",
1160 pamh->include_depth,
1161 pam_trace_cname(pamh),
1162 function_name, (void *)pamh, flags,
1163 pam_strerror(pamh,
1164 required_error ? required_error :
1165 err));
1166 err = required_error ?
1167 required_error : err;
1168 goto exit_return;
1169 } else if (modulep->pam_flag & PAM_REQRD_BIND) {
1170 if (!required_error)
1171 required_error = err;
1172 } else {
1173 if (!optional_error)
1174 optional_error = err;
1175 }
1176 pam_trace(PAM_DEBUG_DEFAULT,
1177 "[%d:%s]:%s(%p, %x): error %s",
1178 pamh->include_depth, pam_trace_cname(pamh),
1179 function_name, (void *)pamh, flags,
1180 pam_strerror(pamh, err));
1181 break;
1182 }
1183 }
1184 modulep = modulep->next;
1185 }
1186
1187 pam_trace(PAM_DEBUG_MODULE, "[%d:%s]:stack_end:%s(%p, %x): %s %s: %s",
1188 pamh->include_depth, pam_trace_cname(pamh), function_name,
1189 (void *)pamh, flags, pamh->include_depth ? "included" : "final",
1190 required_error ? "required" : success ? "success" :
1191 optional_error ? "optional" : "default",
1192 pam_strerror(pamh, required_error ? required_error :
1193 success ? PAM_SUCCESS : optional_error ? optional_error : def_err));
1194 if (pamh->include_depth > 0) {
1195 free_pam_conf_info(pamh);
1196 pamh->include_depth--;
1197 /* continue at next entry */
1198 modulep = pamh->pam_conf_modulep[pamh->include_depth];
1199 pam_trace(PAM_DEBUG_MODULE, "looping for include[%d:%p]",
1200 pamh->include_depth, (void *)modulep);
1201 goto include;
1202 }
1203 free_pam_conf_info(pamh);
1204 pamh->pam_inmodule = RW_OK;
1205 if (required_error != 0)
1206 return (required_error);
1207 else if (success != 0)
1208 return (PAM_SUCCESS);
1209 else if (optional_error != 0)
1210 return (optional_error);
1211 else
1212 return (def_err);
1213
1214 exit_return:
1215 /*
1216 * All done at whatever depth we're at.
1217 * Go back to not having read /etc/pam.conf
1218 */
1219 while (pamh->include_depth > 0) {
1220 free_pam_conf_info(pamh);
1221 pamh->include_depth--;
1222 }
1223 free_pam_conf_info(pamh);
1224 pamh->pam_inmodule = RW_OK;
1225 return (err);
1226 }
1227
1228 /*
1229 * pam_authenticate - authenticate a user
1230 */
1231
1232 int
pam_authenticate(pam_handle_t * pamh,int flags)1233 pam_authenticate(pam_handle_t *pamh, int flags)
1234 {
1235 int retval;
1236
1237 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_AUTH_ERR,
1238 PAM_AUTHENTICATE, "pam_authenticate");
1239
1240 if (retval != PAM_SUCCESS)
1241 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1242 return (retval);
1243 }
1244
1245 /*
1246 * pam_setcred - modify or retrieve user credentials
1247 */
1248
1249 int
pam_setcred(pam_handle_t * pamh,int flags)1250 pam_setcred(pam_handle_t *pamh, int flags)
1251 {
1252 int retval;
1253
1254 retval = run_stack(pamh, flags, PAM_AUTH_MODULE, PAM_CRED_ERR,
1255 PAM_SETCRED, "pam_setcred");
1256
1257 if (retval != PAM_SUCCESS)
1258 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1259 return (retval);
1260 }
1261
1262 /*
1263 * pam_acct_mgmt - check password aging, account expiration
1264 */
1265
1266 int
pam_acct_mgmt(pam_handle_t * pamh,int flags)1267 pam_acct_mgmt(pam_handle_t *pamh, int flags)
1268 {
1269 int retval;
1270
1271 retval = run_stack(pamh, flags, PAM_ACCOUNT_MODULE, PAM_ACCT_EXPIRED,
1272 PAM_ACCT_MGMT, "pam_acct_mgmt");
1273
1274 if (retval != PAM_SUCCESS &&
1275 retval != PAM_NEW_AUTHTOK_REQD) {
1276 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1277 }
1278 return (retval);
1279 }
1280
1281 /*
1282 * pam_open_session - begin session management
1283 */
1284
1285 int
pam_open_session(pam_handle_t * pamh,int flags)1286 pam_open_session(pam_handle_t *pamh, int flags)
1287 {
1288 int retval;
1289
1290 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR,
1291 PAM_OPEN_SESSION, "pam_open_session");
1292
1293 if (retval != PAM_SUCCESS)
1294 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1295 return (retval);
1296 }
1297
1298 /*
1299 * pam_close_session - terminate session management
1300 */
1301
1302 int
pam_close_session(pam_handle_t * pamh,int flags)1303 pam_close_session(pam_handle_t *pamh, int flags)
1304 {
1305 int retval;
1306
1307 retval = run_stack(pamh, flags, PAM_SESSION_MODULE, PAM_SESSION_ERR,
1308 PAM_CLOSE_SESSION, "pam_close_session");
1309
1310 if (retval != PAM_SUCCESS)
1311 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1312 return (retval);
1313 }
1314
1315 /*
1316 * pam_chauthtok - change user authentication token
1317 */
1318
1319 int
pam_chauthtok(pam_handle_t * pamh,int flags)1320 pam_chauthtok(pam_handle_t *pamh, int flags)
1321 {
1322 int retval;
1323
1324 /* do not let apps use PAM_PRELIM_CHECK or PAM_UPDATE_AUTHTOK */
1325 if (flags & (PAM_PRELIM_CHECK | PAM_UPDATE_AUTHTOK)) {
1326 pam_trace(PAM_DEBUG_DEFAULT,
1327 "pam_chauthtok(%p, %x): %s", (void *)pamh, flags,
1328 pam_strerror(pamh, PAM_SYMBOL_ERR));
1329 return (PAM_SYMBOL_ERR);
1330 }
1331
1332 /* 1st pass: PRELIM CHECK */
1333 retval = run_stack(pamh, flags | PAM_PRELIM_CHECK, PAM_PASSWORD_MODULE,
1334 PAM_AUTHTOK_ERR, PAM_CHAUTHTOK, "pam_chauthtok-prelim");
1335
1336 if (retval == PAM_TRY_AGAIN)
1337 return (retval);
1338
1339 if (retval != PAM_SUCCESS) {
1340 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1341 return (retval);
1342 }
1343
1344 /* 2nd pass: UPDATE AUTHTOK */
1345 retval = run_stack(pamh, flags | PAM_UPDATE_AUTHTOK,
1346 PAM_PASSWORD_MODULE, PAM_AUTHTOK_ERR, PAM_CHAUTHTOK,
1347 "pam_chauthtok-update");
1348
1349 if (retval != PAM_SUCCESS)
1350 (void) pam_set_item(pamh, PAM_AUTHTOK, NULL);
1351
1352 return (retval);
1353 }
1354
1355 /*
1356 * pam_putenv - add an environment variable to the PAM handle
1357 * if name_value == 'NAME=VALUE' then set variable to the value
1358 * if name_value == 'NAME=' then set variable to an empty value
1359 * if name_value == 'NAME' then delete the variable
1360 */
1361
1362 int
pam_putenv(pam_handle_t * pamh,const char * name_value)1363 pam_putenv(pam_handle_t *pamh, const char *name_value)
1364 {
1365 int error = PAM_SYSTEM_ERR;
1366 char *equal_sign = 0;
1367 char *name = NULL, *value = NULL, *tmp_value = NULL;
1368 env_list *traverse, *trail;
1369
1370 pam_trace(PAM_DEBUG_DEFAULT,
1371 "pam_putenv(%p, %s)", (void *)pamh,
1372 name_value ? name_value : "NULL");
1373
1374 if (pamh == NULL || name_value == NULL)
1375 goto out;
1376
1377 /* see if we were passed 'NAME=VALUE', 'NAME=', or 'NAME' */
1378 if ((equal_sign = strchr(name_value, '=')) != 0) {
1379 if ((name = calloc(equal_sign - name_value + 1,
1380 sizeof (char))) == 0) {
1381 error = PAM_BUF_ERR;
1382 goto out;
1383 }
1384 (void) strncpy(name, name_value, equal_sign - name_value);
1385 if ((value = strdup(++equal_sign)) == 0) {
1386 error = PAM_BUF_ERR;
1387 goto out;
1388 }
1389 } else {
1390 if ((name = strdup(name_value)) == 0) {
1391 error = PAM_BUF_ERR;
1392 goto out;
1393 }
1394 }
1395
1396 /* check to see if we already have this variable in the PAM handle */
1397 traverse = pamh->pam_env;
1398 trail = traverse;
1399 while (traverse && strncmp(traverse->name, name, strlen(name))) {
1400 trail = traverse;
1401 traverse = traverse->next;
1402 }
1403
1404 if (traverse) {
1405 /* found a match */
1406 if (value == 0) {
1407 /* remove the env variable */
1408 if (pamh->pam_env == traverse)
1409 pamh->pam_env = traverse->next;
1410 else
1411 trail->next = traverse->next;
1412 free_env(traverse);
1413 } else if (strlen(value) == 0) {
1414 /* set env variable to empty value */
1415 if ((tmp_value = strdup("")) == 0) {
1416 error = PAM_SYSTEM_ERR;
1417 goto out;
1418 }
1419 free(traverse->value);
1420 traverse->value = tmp_value;
1421 } else {
1422 /* set the new value */
1423 if ((tmp_value = strdup(value)) == 0) {
1424 error = PAM_SYSTEM_ERR;
1425 goto out;
1426 }
1427 free(traverse->value);
1428 traverse->value = tmp_value;
1429 }
1430
1431 } else if (traverse == 0 && value) {
1432 /*
1433 * could not find a match in the PAM handle.
1434 * add the new value if there is one
1435 */
1436 if ((traverse = calloc(1, sizeof (env_list))) == 0) {
1437 error = PAM_BUF_ERR;
1438 goto out;
1439 }
1440 if ((traverse->name = strdup(name)) == 0) {
1441 free_env(traverse);
1442 error = PAM_BUF_ERR;
1443 goto out;
1444 }
1445 if ((traverse->value = strdup(value)) == 0) {
1446 free_env(traverse);
1447 error = PAM_BUF_ERR;
1448 goto out;
1449 }
1450 if (trail == 0) {
1451 /* new head of list */
1452 pamh->pam_env = traverse;
1453 } else {
1454 /* adding to end of list */
1455 trail->next = traverse;
1456 }
1457 }
1458
1459 error = PAM_SUCCESS;
1460 out:
1461 if (error != PAM_SUCCESS) {
1462 if (traverse) {
1463 if (traverse->name)
1464 free(traverse->name);
1465 if (traverse->value)
1466 free(traverse->value);
1467 free(traverse);
1468 }
1469 }
1470 if (name)
1471 free(name);
1472 if (value)
1473 free(value);
1474 return (error);
1475 }
1476
1477 /*
1478 * pam_getenv - retrieve an environment variable from the PAM handle
1479 */
1480 char *
pam_getenv(pam_handle_t * pamh,const char * name)1481 pam_getenv(pam_handle_t *pamh, const char *name)
1482 {
1483 int error = PAM_SYSTEM_ERR;
1484 env_list *traverse;
1485
1486 pam_trace(PAM_DEBUG_DEFAULT,
1487 "pam_getenv(%p, %p)", (void *)pamh, (void *)name);
1488
1489 if (pamh == NULL || name == NULL)
1490 goto out;
1491
1492 /* check to see if we already have this variable in the PAM handle */
1493 traverse = pamh->pam_env;
1494 while (traverse && strncmp(traverse->name, name, strlen(name))) {
1495 traverse = traverse->next;
1496 }
1497 error = (traverse ? PAM_SUCCESS : PAM_SYSTEM_ERR);
1498 pam_trace(PAM_DEBUG_DEFAULT,
1499 "pam_getenv(%p, %s)=%s", (void *)pamh, name,
1500 traverse ? traverse->value : "NULL");
1501 out:
1502 return (error ? NULL : strdup(traverse->value));
1503 }
1504
1505 /*
1506 * pam_getenvlist - retrieve all environment variables from the PAM handle
1507 * in a NULL terminated array. On error, return NULL.
1508 */
1509 char **
pam_getenvlist(pam_handle_t * pamh)1510 pam_getenvlist(pam_handle_t *pamh)
1511 {
1512 int error = PAM_SYSTEM_ERR;
1513 char **list = 0;
1514 int length = 0;
1515 env_list *traverse;
1516 char *tenv;
1517 size_t tenv_size;
1518
1519 pam_trace(PAM_DEBUG_DEFAULT,
1520 "pam_getenvlist(%p)", (void *)pamh);
1521
1522 if (pamh == NULL)
1523 goto out;
1524
1525 /* find out how many environment variables we have */
1526 traverse = pamh->pam_env;
1527 while (traverse) {
1528 length++;
1529 traverse = traverse->next;
1530 }
1531
1532 /* allocate the array we will return to the caller */
1533 if ((list = calloc(length + 1, sizeof (char *))) == NULL) {
1534 error = PAM_BUF_ERR;
1535 goto out;
1536 }
1537
1538 /* add the variables one by one */
1539 length = 0;
1540 traverse = pamh->pam_env;
1541 while (traverse != NULL) {
1542 tenv_size = strlen(traverse->name) +
1543 strlen(traverse->value) + 2; /* name=val\0 */
1544 if ((tenv = malloc(tenv_size)) == NULL) {
1545 error = PAM_BUF_ERR;
1546 goto out;
1547 }
1548 /*LINTED*/
1549 (void) sprintf(tenv, "%s=%s", traverse->name, traverse->value);
1550 list[length++] = tenv;
1551 traverse = traverse->next;
1552 }
1553 list[length] = NULL;
1554
1555 error = PAM_SUCCESS;
1556 out:
1557 if (error != PAM_SUCCESS) {
1558 /* free the partially constructed list */
1559 if (list) {
1560 length = 0;
1561 while (list[length] != NULL) {
1562 free(list[length]);
1563 length++;
1564 }
1565 free(list);
1566 }
1567 }
1568 return (error ? NULL : list);
1569 }
1570
1571 /*
1572 * Routines to load a requested module on demand
1573 */
1574
1575 /*
1576 * load_modules - load the requested module.
1577 * if the dlopen or dlsym fail, then
1578 * the module is ignored.
1579 */
1580
1581 static int
load_modules(pam_handle_t * pamh,int type,char * function_name,pamtab_t * pam_entry)1582 load_modules(pam_handle_t *pamh, int type, char *function_name,
1583 pamtab_t *pam_entry)
1584 {
1585 void *mh;
1586 struct auth_module *authp;
1587 struct account_module *accountp;
1588 struct session_module *sessionp;
1589 struct password_module *passwdp;
1590 int loading_functions = 0; /* are we currently loading functions? */
1591
1592 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=%s:%s",
1593 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
1594 function_name, pam_trace_fname(pam_entry->pam_flag),
1595 pam_entry->module_path);
1596
1597 while (pam_entry != NULL) {
1598 pam_trace(PAM_DEBUG_DEFAULT,
1599 "while load_modules[%d:%s](%p, %s)=%s",
1600 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
1601 function_name, pam_entry->module_path);
1602
1603 if (pam_entry->pam_flag & PAM_INCLUDE) {
1604 pam_trace(PAM_DEBUG_DEFAULT,
1605 "done load_modules[%d:%s](%p, %s)=%s",
1606 pamh->include_depth, pam_trace_cname(pamh),
1607 (void *)pamh, function_name,
1608 pam_entry->module_path);
1609 return (PAM_SUCCESS);
1610 }
1611 switch (type) {
1612 case PAM_AUTH_MODULE:
1613
1614 /* if the function has already been loaded, return */
1615 authp = pam_entry->function_ptr;
1616 if (!loading_functions &&
1617 (((strcmp(function_name, PAM_SM_AUTHENTICATE)
1618 == 0) && authp && authp->pam_sm_authenticate) ||
1619 ((strcmp(function_name, PAM_SM_SETCRED) == 0) &&
1620 authp && authp->pam_sm_setcred))) {
1621 return (PAM_SUCCESS);
1622 }
1623
1624 /* function has not been loaded yet */
1625 loading_functions = 1;
1626 if (authp == NULL) {
1627 authp = calloc(1, sizeof (struct auth_module));
1628 if (authp == NULL)
1629 return (PAM_BUF_ERR);
1630 }
1631
1632 /* if open_module fails, return error */
1633 if ((mh = open_module(pamh,
1634 pam_entry->module_path)) == NULL) {
1635 __pam_log(LOG_AUTH | LOG_ERR,
1636 "load_modules[%d:%s]: can not open module "
1637 "%s", pamh->include_depth,
1638 pam_trace_cname(pamh),
1639 pam_entry->module_path);
1640 free(authp);
1641 return (PAM_OPEN_ERR);
1642 }
1643
1644 /* load the authentication function */
1645 if (strcmp(function_name, PAM_SM_AUTHENTICATE) == 0) {
1646 if (load_function(mh, PAM_SM_AUTHENTICATE,
1647 &authp->pam_sm_authenticate)
1648 != PAM_SUCCESS) {
1649 /* return error if dlsym fails */
1650 free(authp);
1651 return (PAM_SYMBOL_ERR);
1652 }
1653
1654 /* load the setcred function */
1655 } else if (strcmp(function_name, PAM_SM_SETCRED) == 0) {
1656 if (load_function(mh, PAM_SM_SETCRED,
1657 &authp->pam_sm_setcred) != PAM_SUCCESS) {
1658 /* return error if dlsym fails */
1659 free(authp);
1660 return (PAM_SYMBOL_ERR);
1661 }
1662 }
1663 pam_entry->function_ptr = authp;
1664 break;
1665 case PAM_ACCOUNT_MODULE:
1666 accountp = pam_entry->function_ptr;
1667 if (!loading_functions &&
1668 (strcmp(function_name, PAM_SM_ACCT_MGMT) == 0) &&
1669 accountp && accountp->pam_sm_acct_mgmt) {
1670 return (PAM_SUCCESS);
1671 }
1672
1673 /*
1674 * If functions are added to the account module,
1675 * verify that one of the other functions hasn't
1676 * already loaded it. See PAM_AUTH_MODULE code.
1677 */
1678 loading_functions = 1;
1679 accountp = calloc(1, sizeof (struct account_module));
1680 if (accountp == NULL)
1681 return (PAM_BUF_ERR);
1682
1683 /* if open_module fails, return error */
1684 if ((mh = open_module(pamh,
1685 pam_entry->module_path)) == NULL) {
1686 __pam_log(LOG_AUTH | LOG_ERR,
1687 "load_modules[%d:%s]: can not open module "
1688 "%s", pamh->include_depth,
1689 pam_trace_cname(pamh),
1690 pam_entry->module_path);
1691 free(accountp);
1692 return (PAM_OPEN_ERR);
1693 }
1694
1695 if (load_function(mh, PAM_SM_ACCT_MGMT,
1696 &accountp->pam_sm_acct_mgmt) != PAM_SUCCESS) {
1697 __pam_log(LOG_AUTH | LOG_ERR,
1698 "load_modules[%d:%s]: pam_sm_acct_mgmt() "
1699 "missing", pamh->include_depth,
1700 pam_trace_cname(pamh));
1701 free(accountp);
1702 return (PAM_SYMBOL_ERR);
1703 }
1704 pam_entry->function_ptr = accountp;
1705 break;
1706 case PAM_SESSION_MODULE:
1707 sessionp = pam_entry->function_ptr;
1708 if (!loading_functions &&
1709 (((strcmp(function_name,
1710 PAM_SM_OPEN_SESSION) == 0) &&
1711 sessionp && sessionp->pam_sm_open_session) ||
1712 ((strcmp(function_name,
1713 PAM_SM_CLOSE_SESSION) == 0) &&
1714 sessionp && sessionp->pam_sm_close_session))) {
1715 return (PAM_SUCCESS);
1716 }
1717
1718 loading_functions = 1;
1719 if (sessionp == NULL) {
1720 sessionp = calloc(1,
1721 sizeof (struct session_module));
1722 if (sessionp == NULL)
1723 return (PAM_BUF_ERR);
1724 }
1725
1726 /* if open_module fails, return error */
1727 if ((mh = open_module(pamh,
1728 pam_entry->module_path)) == NULL) {
1729 __pam_log(LOG_AUTH | LOG_ERR,
1730 "load_modules[%d:%s]: can not open module "
1731 "%s", pamh->include_depth,
1732 pam_trace_cname(pamh),
1733 pam_entry->module_path);
1734 free(sessionp);
1735 return (PAM_OPEN_ERR);
1736 }
1737
1738 if ((strcmp(function_name, PAM_SM_OPEN_SESSION) == 0) &&
1739 load_function(mh, PAM_SM_OPEN_SESSION,
1740 &sessionp->pam_sm_open_session) != PAM_SUCCESS) {
1741 free(sessionp);
1742 return (PAM_SYMBOL_ERR);
1743 } else if ((strcmp(function_name,
1744 PAM_SM_CLOSE_SESSION) == 0) &&
1745 load_function(mh, PAM_SM_CLOSE_SESSION,
1746 &sessionp->pam_sm_close_session) != PAM_SUCCESS) {
1747 free(sessionp);
1748 return (PAM_SYMBOL_ERR);
1749 }
1750 pam_entry->function_ptr = sessionp;
1751 break;
1752 case PAM_PASSWORD_MODULE:
1753 passwdp = pam_entry->function_ptr;
1754 if (!loading_functions &&
1755 (strcmp(function_name, PAM_SM_CHAUTHTOK) == 0) &&
1756 passwdp && passwdp->pam_sm_chauthtok) {
1757 return (PAM_SUCCESS);
1758 }
1759
1760 /*
1761 * If functions are added to the password module,
1762 * verify that one of the other functions hasn't
1763 * already loaded it. See PAM_AUTH_MODULE code.
1764 */
1765 loading_functions = 1;
1766 passwdp = calloc(1, sizeof (struct password_module));
1767 if (passwdp == NULL)
1768 return (PAM_BUF_ERR);
1769
1770 /* if open_module fails, continue */
1771 if ((mh = open_module(pamh,
1772 pam_entry->module_path)) == NULL) {
1773 __pam_log(LOG_AUTH | LOG_ERR,
1774 "load_modules[%d:%s]: can not open module "
1775 "%s", pamh->include_depth,
1776 pam_trace_cname(pamh),
1777 pam_entry->module_path);
1778 free(passwdp);
1779 return (PAM_OPEN_ERR);
1780 }
1781
1782 if (load_function(mh, PAM_SM_CHAUTHTOK,
1783 &passwdp->pam_sm_chauthtok) != PAM_SUCCESS) {
1784 free(passwdp);
1785 return (PAM_SYMBOL_ERR);
1786 }
1787 pam_entry->function_ptr = passwdp;
1788 break;
1789 default:
1790 pam_trace(PAM_DEBUG_DEFAULT,
1791 "load_modules[%d:%s](%p, %s): unsupported type %d",
1792 pamh->include_depth, pam_trace_cname(pamh),
1793 (void *)pamh, function_name, type);
1794 break;
1795 }
1796
1797 pam_entry = pam_entry->next;
1798 } /* while */
1799
1800 pam_trace(PAM_DEBUG_MODULE, "load_modules[%d:%s](%p, %s)=done",
1801 pamh->include_depth, pam_trace_cname(pamh), (void *)pamh,
1802 function_name);
1803
1804 return (PAM_SUCCESS);
1805 }
1806
1807 /*
1808 * open_module - Open the module first checking for
1809 * propers modes and ownerships on the file.
1810 */
1811
1812 static void *
open_module(pam_handle_t * pamh,char * module_so)1813 open_module(pam_handle_t *pamh, char *module_so)
1814 {
1815 struct stat64 stb;
1816 char *errmsg;
1817 void *lfd;
1818 fd_list *module_fds = 0;
1819 fd_list *trail = 0;
1820 fd_list *traverse = 0;
1821
1822 /* Check the ownership and file modes */
1823 if (stat64(module_so, &stb) < 0) {
1824 __pam_log(LOG_AUTH | LOG_ERR,
1825 "open_module[%d:%s]: stat(%s) failed: %s",
1826 pamh->include_depth, pam_trace_cname(pamh), module_so,
1827 strerror(errno));
1828 return (NULL);
1829 }
1830 if (stb.st_uid != (uid_t)0) {
1831 __pam_log(LOG_AUTH | LOG_ALERT,
1832 "open_module[%d:%s]: Owner of the module %s is not root",
1833 pamh->include_depth, pam_trace_cname(pamh), module_so);
1834 return (NULL);
1835 }
1836 if (stb.st_mode & S_IWGRP) {
1837 __pam_log(LOG_AUTH | LOG_ALERT,
1838 "open_module[%d:%s]: module %s writable by group",
1839 pamh->include_depth, pam_trace_cname(pamh), module_so);
1840 return (NULL);
1841 }
1842 if (stb.st_mode & S_IWOTH) {
1843 __pam_log(LOG_AUTH | LOG_ALERT,
1844 "open_module[%d:%s]: module %s writable by world",
1845 pamh->include_depth, pam_trace_cname(pamh), module_so);
1846 return (NULL);
1847 }
1848
1849 /*
1850 * Perform the dlopen()
1851 */
1852 lfd = (void *)dlopen(module_so, RTLD_LAZY);
1853
1854 if (lfd == NULL) {
1855 errmsg = dlerror();
1856 __pam_log(LOG_AUTH | LOG_ERR, "open_module[%d:%s]: %s "
1857 "failed: %s", pamh->include_depth, pam_trace_cname(pamh),
1858 module_so, errmsg != NULL ? errmsg : "Unknown error");
1859 return (NULL);
1860 } else {
1861 /* add this fd to the pam handle */
1862 if ((module_fds = calloc(1, sizeof (fd_list))) == 0) {
1863 (void) dlclose(lfd);
1864 lfd = 0;
1865 return (NULL);
1866 }
1867 module_fds->mh = lfd;
1868
1869 if (pamh->fd == 0) {
1870 /* adding new head of list */
1871 pamh->fd = module_fds;
1872 } else {
1873 /* appending to end of list */
1874 traverse = pamh->fd;
1875 while (traverse) {
1876 trail = traverse;
1877 traverse = traverse->next;
1878 }
1879 trail->next = module_fds;
1880 }
1881 }
1882
1883 return (lfd);
1884 }
1885
1886 /*
1887 * load_function - call dlsym() to resolve the function address
1888 */
1889 static int
load_function(void * lfd,char * name,int (** func)())1890 load_function(void *lfd, char *name, int (**func)())
1891 {
1892 char *errmsg = NULL;
1893
1894 if (lfd == NULL)
1895 return (PAM_SYMBOL_ERR);
1896
1897 *func = (int (*)())dlsym(lfd, name);
1898 if (*func == NULL) {
1899 errmsg = dlerror();
1900 __pam_log(LOG_AUTH | LOG_ERR, "dlsym failed %s: error %s",
1901 name, errmsg != NULL ? errmsg : "Unknown error");
1902 return (PAM_SYMBOL_ERR);
1903 }
1904
1905 pam_trace(PAM_DEBUG_DEFAULT,
1906 "load_function: successful load of %s", name);
1907 return (PAM_SUCCESS);
1908 }
1909
1910 /*
1911 * Routines to read the pam.conf configuration file
1912 */
1913
1914 /*
1915 * open_pam_conf - open the pam.conf config file
1916 */
1917
1918 static int
open_pam_conf(struct pam_fh ** pam_fh,pam_handle_t * pamh,char * config)1919 open_pam_conf(struct pam_fh **pam_fh, pam_handle_t *pamh, char *config)
1920 {
1921 struct stat64 stb;
1922 int fd;
1923
1924 if ((fd = open(config, O_RDONLY)) == -1) {
1925 __pam_log(LOG_AUTH | LOG_ALERT,
1926 "open_pam_conf[%d:%s]: open(%s) failed: %s",
1927 pamh->include_depth, pam_trace_cname(pamh), config,
1928 strerror(errno));
1929 return (0);
1930 }
1931 /* Check the ownership and file modes */
1932 if (fstat64(fd, &stb) < 0) {
1933 __pam_log(LOG_AUTH | LOG_ALERT,
1934 "open_pam_conf[%d:%s]: stat(%s) failed: %s",
1935 pamh->include_depth, pam_trace_cname(pamh), config,
1936 strerror(errno));
1937 (void) close(fd);
1938 return (0);
1939 }
1940 if (stb.st_uid != (uid_t)0) {
1941 __pam_log(LOG_AUTH | LOG_ALERT,
1942 "open_pam_conf[%d:%s]: Owner of %s is not root",
1943 pamh->include_depth, pam_trace_cname(pamh), config);
1944 (void) close(fd);
1945 return (0);
1946 }
1947 if (stb.st_mode & S_IWGRP) {
1948 __pam_log(LOG_AUTH | LOG_ALERT,
1949 "open_pam_conf[%d:%s]: %s writable by group",
1950 pamh->include_depth, pam_trace_cname(pamh), config);
1951 (void) close(fd);
1952 return (0);
1953 }
1954 if (stb.st_mode & S_IWOTH) {
1955 __pam_log(LOG_AUTH | LOG_ALERT,
1956 "open_pam_conf[%d:%s]: %s writable by world",
1957 pamh->include_depth, pam_trace_cname(pamh), config);
1958 (void) close(fd);
1959 return (0);
1960 }
1961 if ((*pam_fh = calloc(1, sizeof (struct pam_fh))) == NULL) {
1962 (void) close(fd);
1963 return (0);
1964 }
1965 (*pam_fh)->fconfig = fd;
1966 (*pam_fh)->bufsize = (size_t)stb.st_size;
1967 if (((*pam_fh)->data = mmap(0, (*pam_fh)->bufsize, PROT_READ,
1968 MAP_PRIVATE, (*pam_fh)->fconfig, 0)) == MAP_FAILED) {
1969 (void) close(fd);
1970 free (*pam_fh);
1971 return (0);
1972 }
1973 (*pam_fh)->bufferp = (*pam_fh)->data;
1974
1975 return (1);
1976 }
1977
1978 /*
1979 * close_pam_conf - close pam.conf
1980 */
1981
1982 static void
close_pam_conf(struct pam_fh * pam_fh)1983 close_pam_conf(struct pam_fh *pam_fh)
1984 {
1985 (void) munmap(pam_fh->data, pam_fh->bufsize);
1986 (void) close(pam_fh->fconfig);
1987 free(pam_fh);
1988 }
1989
1990 /*
1991 * read_pam_conf - read in each entry in pam.conf and store info
1992 * under the pam handle.
1993 */
1994
1995 static int
read_pam_conf(pam_handle_t * pamh,char * config)1996 read_pam_conf(pam_handle_t *pamh, char *config)
1997 {
1998 struct pam_fh *pam_fh;
1999 pamtab_t *pamentp;
2000 pamtab_t *tpament;
2001 char *service;
2002 int error;
2003 int i = pamh->include_depth; /* include depth */
2004 /*
2005 * service types:
2006 * error (-1), "auth" (0), "account" (1), "session" (2), "password" (3)
2007 */
2008 int service_found[PAM_NUM_MODULE_TYPES+1] = {0, 0, 0, 0, 0};
2009
2010 (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
2011 if (service == NULL || *service == '\0') {
2012 __pam_log(LOG_AUTH | LOG_ERR, "No service name");
2013 return (PAM_SYSTEM_ERR);
2014 }
2015
2016 pamh->pam_conf_name[i] = strdup(config);
2017 pam_trace(PAM_DEBUG_CONF, "read_pam_conf[%d:%s](%p) open(%s)",
2018 i, pam_trace_cname(pamh), (void *)pamh, config);
2019 if (open_pam_conf(&pam_fh, pamh, config) == 0) {
2020 return (PAM_SYSTEM_ERR);
2021 }
2022
2023 while ((error =
2024 get_pam_conf_entry(pam_fh, pamh, &pamentp)) == PAM_SUCCESS &&
2025 pamentp) {
2026
2027 /* See if entry is this service and valid */
2028 if (verify_pam_conf(pamentp, service)) {
2029 pam_trace(PAM_DEBUG_CONF,
2030 "read_pam_conf[%d:%s](%p): bad entry error %s",
2031 i, pam_trace_cname(pamh), (void *)pamh, service);
2032
2033 error = PAM_SYSTEM_ERR;
2034 free_pamconf(pamentp);
2035 goto out;
2036 }
2037 if (strcasecmp(pamentp->pam_service, service) == 0) {
2038 pam_trace(PAM_DEBUG_CONF,
2039 "read_pam_conf[%d:%s](%p): processing %s",
2040 i, pam_trace_cname(pamh), (void *)pamh, service);
2041 /* process first service entry */
2042 if (service_found[pamentp->pam_type + 1] == 0) {
2043 /* purge "other" entries */
2044 while ((tpament = pamh->pam_conf_info[i]
2045 [pamentp->pam_type]) != NULL) {
2046 pam_trace(PAM_DEBUG_CONF,
2047 "read_pam_conf(%p): purging "
2048 "\"other\"[%d:%s][%s]",
2049 (void *)pamh, i,
2050 pam_trace_cname(pamh),
2051 pam_snames[pamentp->pam_type]);
2052 pamh->pam_conf_info[i]
2053 [pamentp->pam_type] = tpament->next;
2054 free_pamconf(tpament);
2055 }
2056 /* add first service entry */
2057 pam_trace(PAM_DEBUG_CONF,
2058 "read_pam_conf(%p): adding 1st "
2059 "%s[%d:%s][%s]",
2060 (void *)pamh, service, i,
2061 pam_trace_cname(pamh),
2062 pam_snames[pamentp->pam_type]);
2063 pamh->pam_conf_info[i][pamentp->pam_type] =
2064 pamentp;
2065 service_found[pamentp->pam_type + 1] = 1;
2066 } else {
2067 /* append more service entries */
2068 pam_trace(PAM_DEBUG_CONF,
2069 "read_pam_conf(%p): adding more "
2070 "%s[%d:%s][%s]",
2071 (void *)pamh, service, i,
2072 pam_trace_cname(pamh),
2073 pam_snames[pamentp->pam_type]);
2074 tpament =
2075 pamh->pam_conf_info[i][pamentp->pam_type];
2076 while (tpament->next != NULL) {
2077 tpament = tpament->next;
2078 }
2079 tpament->next = pamentp;
2080 }
2081 } else if (service_found[pamentp->pam_type + 1] == 0) {
2082 /* See if "other" entry available and valid */
2083 if (verify_pam_conf(pamentp, "other")) {
2084 pam_trace(PAM_DEBUG_CONF,
2085 "read_pam_conf(%p): bad entry error %s "
2086 "\"other\"[%d:%s]",
2087 (void *)pamh, service, i,
2088 pam_trace_cname(pamh));
2089 error = PAM_SYSTEM_ERR;
2090 free_pamconf(pamentp);
2091 goto out;
2092 }
2093 if (strcasecmp(pamentp->pam_service, "other") == 0) {
2094 pam_trace(PAM_DEBUG_CONF,
2095 "read_pam_conf(%p): processing "
2096 "\"other\"[%d:%s]", (void *)pamh, i,
2097 pam_trace_cname(pamh));
2098 if ((tpament = pamh->pam_conf_info[i]
2099 [pamentp->pam_type]) == NULL) {
2100 /* add first "other" entry */
2101 pam_trace(PAM_DEBUG_CONF,
2102 "read_pam_conf(%p): adding 1st "
2103 "other[%d:%s][%s]", (void *)pamh, i,
2104 pam_trace_cname(pamh),
2105 pam_snames[pamentp->pam_type]);
2106 pamh->pam_conf_info[i]
2107 [pamentp->pam_type] = pamentp;
2108 } else {
2109 /* append more "other" entries */
2110 pam_trace(PAM_DEBUG_CONF,
2111 "read_pam_conf(%p): adding more "
2112 "other[%d:%s][%s]", (void *)pamh, i,
2113 pam_trace_cname(pamh),
2114 pam_snames[pamentp->pam_type]);
2115 while (tpament->next != NULL) {
2116 tpament = tpament->next;
2117 }
2118 tpament->next = pamentp;
2119 }
2120 } else {
2121 /* irrelevant entry */
2122 free_pamconf(pamentp);
2123 }
2124 } else {
2125 /* irrelevant entry */
2126 free_pamconf(pamentp);
2127 }
2128 }
2129 out:
2130 (void) close_pam_conf(pam_fh);
2131 if (error != PAM_SUCCESS)
2132 free_pam_conf_info(pamh);
2133 return (error);
2134 }
2135
2136 /*
2137 * get_pam_conf_entry - get a pam.conf entry
2138 */
2139
2140 static int
get_pam_conf_entry(struct pam_fh * pam_fh,pam_handle_t * pamh,pamtab_t ** pam)2141 get_pam_conf_entry(struct pam_fh *pam_fh, pam_handle_t *pamh, pamtab_t **pam)
2142 {
2143 char *cp, *arg;
2144 int argc;
2145 char *tmp, *tmp_free;
2146 int i;
2147 char *current_line = NULL;
2148 int error = PAM_SYSTEM_ERR; /* preset to error */
2149 int err;
2150
2151 /* get the next line from pam.conf */
2152 if ((cp = nextline(pam_fh, pamh, &err)) == NULL) {
2153 /* no more lines in pam.conf ==> return */
2154 error = PAM_SUCCESS;
2155 *pam = NULL;
2156 goto out;
2157 }
2158
2159 if ((*pam = calloc(1, sizeof (pamtab_t))) == NULL) {
2160 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2161 goto out;
2162 }
2163
2164 /* copy full line for error reporting */
2165 if ((current_line = strdup(cp)) == NULL) {
2166 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2167 goto out;
2168 }
2169
2170 pam_trace(PAM_DEBUG_CONF,
2171 "pam.conf[%s] entry:\t%s", pam_trace_cname(pamh), current_line);
2172
2173 /* get service name (e.g. login, su, passwd) */
2174 if ((arg = read_next_token(&cp)) == 0) {
2175 __pam_log(LOG_AUTH | LOG_CRIT,
2176 "illegal pam.conf[%s] entry: %s: missing SERVICE NAME",
2177 pam_trace_cname(pamh), current_line);
2178 goto out;
2179 }
2180 if (((*pam)->pam_service = strdup(arg)) == 0) {
2181 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2182 goto out;
2183 }
2184
2185 /* get module type (e.g. authentication, acct mgmt) */
2186 if ((arg = read_next_token(&cp)) == 0) {
2187 __pam_log(LOG_AUTH | LOG_CRIT,
2188 "illegal pam.conf[%s] entry: %s: missing MODULE TYPE",
2189 pam_trace_cname(pamh), current_line);
2190 (*pam)->pam_type = -1; /* 0 is a valid value */
2191 goto getflag;
2192 }
2193 if (strcasecmp(arg, PAM_AUTH_NAME) == 0) {
2194 (*pam)->pam_type = PAM_AUTH_MODULE;
2195 } else if (strcasecmp(arg, PAM_ACCOUNT_NAME) == 0) {
2196 (*pam)->pam_type = PAM_ACCOUNT_MODULE;
2197 } else if (strcasecmp(arg, PAM_SESSION_NAME) == 0) {
2198 (*pam)->pam_type = PAM_SESSION_MODULE;
2199 } else if (strcasecmp(arg, PAM_PASSWORD_NAME) == 0) {
2200 (*pam)->pam_type = PAM_PASSWORD_MODULE;
2201 } else {
2202 /* error */
2203 __pam_log(LOG_AUTH | LOG_CRIT,
2204 "illegal pam.conf[%s] entry: %s: invalid module "
2205 "type: %s", pam_trace_cname(pamh), current_line, arg);
2206 (*pam)->pam_type = -1; /* 0 is a valid value */
2207 }
2208
2209 getflag:
2210 /* get pam flag (e.g., requisite, required, sufficient, optional) */
2211 if ((arg = read_next_token(&cp)) == 0) {
2212 __pam_log(LOG_AUTH | LOG_CRIT,
2213 "illegal pam.conf[%s] entry: %s: missing CONTROL FLAG",
2214 pam_trace_cname(pamh), current_line);
2215 goto getpath;
2216 }
2217 if (strcasecmp(arg, PAM_BINDING_NAME) == 0) {
2218 (*pam)->pam_flag = PAM_BINDING;
2219 } else if (strcasecmp(arg, PAM_INCLUDE_NAME) == 0) {
2220 (*pam)->pam_flag = PAM_INCLUDE;
2221 } else if (strcasecmp(arg, PAM_OPTIONAL_NAME) == 0) {
2222 (*pam)->pam_flag = PAM_OPTIONAL;
2223 } else if (strcasecmp(arg, PAM_REQUIRED_NAME) == 0) {
2224 (*pam)->pam_flag = PAM_REQUIRED;
2225 } else if (strcasecmp(arg, PAM_REQUISITE_NAME) == 0) {
2226 (*pam)->pam_flag = PAM_REQUISITE;
2227 } else if (strcasecmp(arg, PAM_SUFFICIENT_NAME) == 0) {
2228 (*pam)->pam_flag = PAM_SUFFICIENT;
2229 } else {
2230 /* error */
2231 __pam_log(LOG_AUTH | LOG_CRIT,
2232 "illegal pam.conf[%s] entry: %s",
2233 pam_trace_cname(pamh), current_line);
2234 __pam_log(LOG_AUTH | LOG_CRIT,
2235 "\tinvalid control flag: %s", arg);
2236 }
2237
2238 getpath:
2239 /* get module path (e.g. /usr/lib/security/pam_unix_auth.so.1) */
2240 if ((arg = read_next_token(&cp)) == 0) {
2241 __pam_log(LOG_AUTH | LOG_CRIT,
2242 "illegal pam.conf[%s] entry: %s: missing MODULE PATH",
2243 pam_trace_cname(pamh), current_line);
2244 error = PAM_SUCCESS; /* success */
2245 goto out;
2246 }
2247 if (arg[0] != '/') {
2248 size_t len;
2249 /*
2250 * If module path does not start with "/", then
2251 * prepend PAM_LIB_DIR (/usr/lib/security/).
2252 */
2253 /* sizeof (PAM_LIB_DIR) has room for '\0' */
2254 len = sizeof (PAM_LIB_DIR) + sizeof (PAM_ISA_DIR) + strlen(arg);
2255 if (((*pam)->module_path = malloc(len)) == NULL) {
2256 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2257 goto out;
2258 }
2259 if ((*pam)->pam_flag & PAM_INCLUDE) {
2260 (void) snprintf((*pam)->module_path, len, "%s%s",
2261 PAM_LIB_DIR, arg);
2262 } else {
2263 (void) snprintf((*pam)->module_path, len, "%s%s%s",
2264 PAM_LIB_DIR, PAM_ISA_DIR, arg);
2265 }
2266 } else {
2267 /* Full path provided for module */
2268 char *isa;
2269
2270 /* Check for Instruction Set Architecture indicator */
2271 if ((isa = strstr(arg, PAM_ISA)) != NULL) {
2272 size_t len;
2273 len = strlen(arg) - (sizeof (PAM_ISA)-1) +
2274 sizeof (PAM_ISA_DIR);
2275
2276 /* substitute the architecture dependent path */
2277 if (((*pam)->module_path = malloc(len)) == NULL) {
2278 __pam_log(LOG_AUTH | LOG_ERR,
2279 "strdup: out of memory");
2280 goto out;
2281 }
2282 *isa = '\000';
2283 isa += strlen(PAM_ISA);
2284 (void) snprintf((*pam)->module_path, len, "%s%s%s",
2285 arg, PAM_ISA_DIR, isa);
2286 } else if (((*pam)->module_path = strdup(arg)) == 0) {
2287 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2288 goto out;
2289 }
2290 }
2291
2292 /* count the number of module-specific options first */
2293 argc = 0;
2294 if ((tmp = strdup(cp)) == NULL) {
2295 __pam_log(LOG_AUTH | LOG_ERR, "strdup: out of memory");
2296 goto out;
2297 }
2298 tmp_free = tmp;
2299 for (arg = read_next_token(&tmp); arg; arg = read_next_token(&tmp))
2300 argc++;
2301 free(tmp_free);
2302
2303 /* allocate array for the module-specific options */
2304 if (argc > 0) {
2305 if (((*pam)->module_argv =
2306 calloc(argc+1, sizeof (char *))) == 0) {
2307 __pam_log(LOG_AUTH | LOG_ERR, "calloc: out of memory");
2308 goto out;
2309 }
2310 i = 0;
2311 for (arg = read_next_token(&cp); arg;
2312 arg = read_next_token(&cp)) {
2313 (*pam)->module_argv[i] = strdup(arg);
2314 if ((*pam)->module_argv[i] == NULL) {
2315 __pam_log(LOG_AUTH | LOG_ERR, "strdup failed");
2316 goto out;
2317 }
2318 i++;
2319 }
2320 (*pam)->module_argv[argc] = NULL;
2321 }
2322 (*pam)->module_argc = argc;
2323
2324 error = PAM_SUCCESS; /* success */
2325 (*pam)->pam_err = err; /* was the line truncated */
2326
2327 out:
2328 if (current_line)
2329 free(current_line);
2330 if (error != PAM_SUCCESS) {
2331 /* on error free this */
2332 if (*pam)
2333 free_pamconf(*pam);
2334 }
2335 return (error);
2336 }
2337
2338
2339 /*
2340 * read_next_token - skip tab and space characters and return the next token
2341 */
2342
2343 static char *
read_next_token(char ** cpp)2344 read_next_token(char **cpp)
2345 {
2346 register char *cp = *cpp;
2347 char *start;
2348
2349 if (cp == (char *)0) {
2350 *cpp = (char *)0;
2351 return ((char *)0);
2352 }
2353 while (*cp == ' ' || *cp == '\t')
2354 cp++;
2355 if (*cp == '\0') {
2356 *cpp = (char *)0;
2357 return ((char *)0);
2358 }
2359 start = cp;
2360 while (*cp && *cp != ' ' && *cp != '\t')
2361 cp++;
2362 if (*cp != '\0')
2363 *cp++ = '\0';
2364 *cpp = cp;
2365 return (start);
2366 }
2367
2368 static char *
pam_conf_strnchr(char * sp,int c,intptr_t count)2369 pam_conf_strnchr(char *sp, int c, intptr_t count)
2370 {
2371 while (count) {
2372 if (*sp == (char)c)
2373 return ((char *)sp);
2374 else {
2375 sp++;
2376 count--;
2377 }
2378 };
2379 return (NULL);
2380 }
2381
2382 /*
2383 * nextline - skip all blank lines and comments
2384 */
2385
2386 static char *
nextline(struct pam_fh * pam_fh,pam_handle_t * pamh,int * err)2387 nextline(struct pam_fh *pam_fh, pam_handle_t *pamh, int *err)
2388 {
2389 char *ll;
2390 int find_a_line = 0;
2391 char *data = pam_fh->data;
2392 char *bufferp = pam_fh->bufferp;
2393 char *bufferendp = &data[pam_fh->bufsize];
2394 size_t input_len;
2395
2396 /*
2397 * Skip the blank line, comment line
2398 */
2399 while (!find_a_line) {
2400 /* if we are at the end of the buffer, there is no next line */
2401 if (bufferp == bufferendp)
2402 return (NULL);
2403
2404 /* skip blank line */
2405 while (*bufferp == '\n') {
2406 /*
2407 * If we are at the end of the buffer, there is
2408 * no next line.
2409 */
2410 if (++bufferp == bufferendp) {
2411 return (NULL);
2412 }
2413 /* else we check *bufferp again */
2414 }
2415
2416 /* skip comment line */
2417 while (*bufferp == '#') {
2418 if ((ll = pam_conf_strnchr(bufferp, '\n',
2419 bufferendp - bufferp)) != NULL) {
2420 bufferp = ll;
2421 } else {
2422 /*
2423 * this comment line the last line.
2424 * no next line
2425 */
2426 return (NULL);
2427 }
2428
2429 /*
2430 * If we are at the end of the buffer, there is
2431 * no next line.
2432 */
2433 if (bufferp == bufferendp) {
2434 return (NULL);
2435 }
2436 }
2437
2438 if ((*bufferp != '\n') && (*bufferp != '#')) {
2439 find_a_line = 1;
2440 }
2441 }
2442
2443 *err = PAM_SUCCESS;
2444 /* now we find one line */
2445 if ((ll = pam_conf_strnchr(bufferp, '\n', bufferendp - bufferp))
2446 != NULL) {
2447 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) {
2448 __pam_log(LOG_AUTH | LOG_ERR,
2449 "nextline[%d:%s]: pam.conf line too long %.256s",
2450 pamh->include_depth, pam_trace_cname(pamh),
2451 bufferp);
2452 input_len = sizeof (pam_fh->line) - 1;
2453 *err = PAM_SERVICE_ERR;
2454 }
2455 (void) strncpy(pam_fh->line, bufferp, input_len);
2456 pam_fh->line[input_len] = '\0';
2457 pam_fh->bufferp = ll++;
2458 } else {
2459 ll = bufferendp;
2460 if ((input_len = ll - bufferp) >= sizeof (pam_fh->line)) {
2461 __pam_log(LOG_AUTH | LOG_ERR,
2462 "nextline[%d:%s]: pam.conf line too long %.256s",
2463 pamh->include_depth, pam_trace_cname(pamh),
2464 bufferp);
2465 input_len = sizeof (pam_fh->line) - 1;
2466 *err = PAM_SERVICE_ERR;
2467 }
2468 (void) strncpy(pam_fh->line, bufferp, input_len);
2469 pam_fh->line[input_len] = '\0';
2470 pam_fh->bufferp = ll;
2471 }
2472
2473 return (pam_fh->line);
2474 }
2475
2476 /*
2477 * verify_pam_conf - verify that the pam_conf entry is filled in.
2478 *
2479 * True = Error if there is no service.
2480 * True = Error if there is a service and it matches the requested service
2481 * but, the type, flag, line overflow, or path is in error.
2482 */
2483
2484 static int
verify_pam_conf(pamtab_t * pam,char * service)2485 verify_pam_conf(pamtab_t *pam, char *service)
2486 {
2487 return ((pam->pam_service == (char *)NULL) ||
2488 ((strcasecmp(pam->pam_service, service) == 0) &&
2489 ((pam->pam_type == -1) ||
2490 (pam->pam_flag == 0) ||
2491 (pam->pam_err != PAM_SUCCESS) ||
2492 (pam->module_path == (char *)NULL))));
2493 }
2494
2495 /*
2496 * Routines to free allocated storage
2497 */
2498
2499 /*
2500 * clean_up - free allocated storage in the pam handle
2501 */
2502
2503 static void
clean_up(pam_handle_t * pamh)2504 clean_up(pam_handle_t *pamh)
2505 {
2506 int i;
2507 pam_repository_t *auth_rep;
2508
2509 if (pamh) {
2510 while (pamh->include_depth >= 0) {
2511 free_pam_conf_info(pamh);
2512 pamh->include_depth--;
2513 }
2514
2515 /* Cleanup PAM_REPOSITORY structure */
2516 auth_rep = pamh->ps_item[PAM_REPOSITORY].pi_addr;
2517 if (auth_rep != NULL) {
2518 if (auth_rep->type != NULL)
2519 free(auth_rep->type);
2520 if (auth_rep->scope != NULL)
2521 free(auth_rep->scope);
2522 }
2523
2524 for (i = 0; i < PAM_MAX_ITEMS; i++) {
2525 if (pamh->ps_item[i].pi_addr != NULL) {
2526 if (i == PAM_AUTHTOK || i == PAM_OLDAUTHTOK) {
2527 (void) memset(pamh->ps_item[i].pi_addr,
2528 0, pamh->ps_item[i].pi_size);
2529 }
2530 free(pamh->ps_item[i].pi_addr);
2531 }
2532 }
2533 free(pamh);
2534 }
2535 }
2536
2537 /*
2538 * free_pamconf - free memory used to store pam.conf entry
2539 */
2540
2541 static void
free_pamconf(pamtab_t * cp)2542 free_pamconf(pamtab_t *cp)
2543 {
2544 int i;
2545
2546 if (cp) {
2547 if (cp->pam_service)
2548 free(cp->pam_service);
2549 if (cp->module_path)
2550 free(cp->module_path);
2551 for (i = 0; i < cp->module_argc; i++) {
2552 if (cp->module_argv[i])
2553 free(cp->module_argv[i]);
2554 }
2555 if (cp->module_argc > 0)
2556 free(cp->module_argv);
2557 if (cp->function_ptr)
2558 free(cp->function_ptr);
2559
2560 free(cp);
2561 }
2562 }
2563
2564 /*
2565 * free_pam_conf_info - free memory used to store all pam.conf info
2566 * under the pam handle
2567 */
2568
2569 static void
free_pam_conf_info(pam_handle_t * pamh)2570 free_pam_conf_info(pam_handle_t *pamh)
2571 {
2572 pamtab_t *pamentp;
2573 pamtab_t *pament_trail;
2574 int i = pamh->include_depth;
2575 int j;
2576
2577 for (j = 0; j < PAM_NUM_MODULE_TYPES; j++) {
2578 pamentp = pamh->pam_conf_info[i][j];
2579 pamh->pam_conf_info[i][j] = NULL;
2580 pament_trail = pamentp;
2581 while (pamentp) {
2582 pamentp = pamentp->next;
2583 free_pamconf(pament_trail);
2584 pament_trail = pamentp;
2585 }
2586 }
2587 if (pamh->pam_conf_name[i] != NULL) {
2588 free(pamh->pam_conf_name[i]);
2589 pamh->pam_conf_name[i] = NULL;
2590 }
2591 }
2592
2593 static void
free_env(env_list * pam_env)2594 free_env(env_list *pam_env)
2595 {
2596 if (pam_env) {
2597 if (pam_env->name)
2598 free(pam_env->name);
2599 if (pam_env->value)
2600 free(pam_env->value);
2601 free(pam_env);
2602 }
2603 }
2604
2605 /*
2606 * Internal convenience functions for Solaris PAM service modules.
2607 */
2608
2609 #include <libintl.h>
2610 #include <nl_types.h>
2611 #include <synch.h>
2612 #include <locale.h>
2613 #include <thread.h>
2614
2615 typedef struct pam_msg_data {
2616 nl_catd fd;
2617 } pam_msg_data_t;
2618
2619 /*
2620 * free_resp():
2621 * free storage for responses used in the call back "pam_conv" functions
2622 */
2623
2624 void
free_resp(int num_msg,struct pam_response * resp)2625 free_resp(int num_msg, struct pam_response *resp)
2626 {
2627 int i;
2628 struct pam_response *r;
2629
2630 if (resp) {
2631 r = resp;
2632 for (i = 0; i < num_msg; i++, r++) {
2633 if (r->resp) {
2634 /* clear before freeing -- may be a password */
2635 bzero(r->resp, strlen(r->resp));
2636 free(r->resp);
2637 r->resp = NULL;
2638 }
2639 }
2640 free(resp);
2641 }
2642 }
2643
2644 static int
do_conv(pam_handle_t * pamh,int msg_style,int num_msg,char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE],void * conv_apdp,struct pam_response * ret_respp[])2645 do_conv(pam_handle_t *pamh, int msg_style, int num_msg,
2646 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp,
2647 struct pam_response *ret_respp[])
2648 {
2649 struct pam_message *msg;
2650 struct pam_message *m;
2651 int i;
2652 int k;
2653 int retcode;
2654 struct pam_conv *pam_convp;
2655
2656 if ((retcode = pam_get_item(pamh, PAM_CONV,
2657 (void **)&pam_convp)) != PAM_SUCCESS) {
2658 return (retcode);
2659 }
2660
2661 /*
2662 * When pam_set_item() is called to set PAM_CONV and the
2663 * item is NULL, memset(pip->pi_addr, 0, size) is called.
2664 * So at this point, we should check whether pam_convp->conv
2665 * is NULL or not.
2666 */
2667 if ((pam_convp == NULL) || (pam_convp->conv == NULL))
2668 return (PAM_SYSTEM_ERR);
2669
2670 i = 0;
2671 k = num_msg;
2672
2673 msg = calloc(num_msg, sizeof (struct pam_message));
2674 if (msg == NULL) {
2675 return (PAM_BUF_ERR);
2676 }
2677 m = msg;
2678
2679 while (k--) {
2680 /*
2681 * fill out the message structure to display prompt message
2682 */
2683 m->msg_style = msg_style;
2684 m->msg = messages[i];
2685 pam_trace(PAM_DEBUG_CONV,
2686 "pam_conv_msg(%p:%d[%d]=%s)",
2687 (void *)pamh, msg_style, i, messages[i]);
2688 m++;
2689 i++;
2690 }
2691
2692 /*
2693 * The UNIX pam modules always calls __pam_get_authtok() and
2694 * __pam_display_msg() with a NULL pointer as the conv_apdp.
2695 * In case the conv_apdp is NULL and the pam_convp->appdata_ptr
2696 * is not NULL, we should pass the pam_convp->appdata_ptr
2697 * to the conversation function.
2698 */
2699 if (conv_apdp == NULL && pam_convp->appdata_ptr != NULL)
2700 conv_apdp = pam_convp->appdata_ptr;
2701
2702 /*
2703 * Call conv function to display the prompt.
2704 */
2705 retcode = (pam_convp->conv)(num_msg, &msg, ret_respp, conv_apdp);
2706 pam_trace(PAM_DEBUG_CONV,
2707 "pam_conv_resp(%p pam_conv = %s) ret_respp = %p",
2708 (void *)pamh, pam_strerror(pamh, retcode), (void *)ret_respp);
2709 if (*ret_respp == NULL) {
2710 pam_trace(PAM_DEBUG_CONV,
2711 "pam_conv_resp(%p No response requested)", (void *)pamh);
2712 } else if ((pam_debug & (PAM_DEBUG_CONV | PAM_DEBUG_AUTHTOK)) != 0) {
2713 struct pam_response *r = *ret_respp;
2714
2715 for (i = 0; i < num_msg; i++, r++) {
2716 if (r->resp == NULL) {
2717 pam_trace(PAM_DEBUG_CONV,
2718 "pam_conv_resp(%p:"
2719 "[%d] NULL response string)",
2720 (void *)pamh, i);
2721 } else {
2722 if (msg_style == PAM_PROMPT_ECHO_OFF) {
2723 #ifdef DEBUG
2724 pam_trace(PAM_DEBUG_AUTHTOK,
2725 "pam_conv_resp(%p:[%d]=%s, "
2726 "code=%d)",
2727 (void *)pamh, i, r->resp,
2728 r->resp_retcode);
2729 #endif /* DEBUG */
2730 pam_trace(PAM_DEBUG_CONV,
2731 "pam_conv_resp(%p:[%d] len=%lu, "
2732 "code=%d)",
2733 (void *)pamh, i,
2734 (ulong_t)strlen(r->resp),
2735 r->resp_retcode);
2736 } else {
2737 pam_trace(PAM_DEBUG_CONV,
2738 "pam_conv_resp(%p:[%d]=%s, "
2739 "code=%d)",
2740 (void *)pamh, i, r->resp,
2741 r->resp_retcode);
2742 }
2743 }
2744 }
2745 }
2746
2747 if (msg)
2748 free(msg);
2749 return (retcode);
2750 }
2751
2752 /*
2753 * __pam_display_msg():
2754 * display message by calling the call back functions
2755 * provided by the application through "pam_conv" structure
2756 */
2757
2758 int
__pam_display_msg(pam_handle_t * pamh,int msg_style,int num_msg,char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE],void * conv_apdp)2759 __pam_display_msg(pam_handle_t *pamh, int msg_style, int num_msg,
2760 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE], void *conv_apdp)
2761 {
2762 struct pam_response *ret_respp = NULL;
2763 int ret;
2764
2765 ret = do_conv(pamh, msg_style, num_msg, messages,
2766 conv_apdp, &ret_respp);
2767
2768 if (ret_respp != NULL)
2769 free_resp(num_msg, ret_respp);
2770
2771 return (ret);
2772 }
2773
2774 /*
2775 * __pam_get_authtok()
2776 * retrieves a password of at most PASS_MAX length from the pam
2777 * handle (pam_get_item) or from the input stream (do_conv).
2778 *
2779 * This function allocates memory for the new authtok.
2780 * Applications calling this function are responsible for
2781 * freeing this memory.
2782 *
2783 * If "source" is
2784 * PAM_HANDLE
2785 * and "type" is:
2786 * PAM_AUTHTOK - password is taken from pam handle (PAM_AUTHTOK)
2787 * PAM_OLDAUTHTOK - password is taken from pam handle (PAM_OLDAUTHTOK)
2788 *
2789 * If "source" is
2790 * PAM_PROMPT
2791 * and "type" is:
2792 * 0: Prompt for new passwd, do not even attempt
2793 * to store it in the pam handle.
2794 * PAM_AUTHTOK: Prompt for new passwd, store in pam handle as
2795 * PAM_AUTHTOK item if this value is not already set.
2796 * PAM_OLDAUTHTOK: Prompt for new passwd, store in pam handle as
2797 * PAM_OLDAUTHTOK item if this value is not
2798 * already set.
2799 */
2800 int
__pam_get_authtok(pam_handle_t * pamh,int source,int type,char * prompt,char ** authtok)2801 __pam_get_authtok(pam_handle_t *pamh, int source, int type, char *prompt,
2802 char **authtok)
2803 {
2804 int error = PAM_SYSTEM_ERR;
2805 char *new_password = NULL;
2806 struct pam_response *ret_resp = NULL;
2807 char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
2808
2809 if ((*authtok = calloc(PASS_MAX+1, sizeof (char))) == NULL)
2810 return (PAM_BUF_ERR);
2811
2812 if (prompt == NULL)
2813 prompt = dgettext(TEXT_DOMAIN, "password: ");
2814
2815 switch (source) {
2816 case PAM_HANDLE:
2817
2818 /* get password from pam handle item list */
2819
2820 switch (type) {
2821 case PAM_AUTHTOK:
2822 case PAM_OLDAUTHTOK:
2823
2824 if ((error = pam_get_item(pamh, type,
2825 (void **)&new_password)) != PAM_SUCCESS)
2826 goto err_ret;
2827
2828 if (new_password == NULL || new_password[0] == '\0') {
2829 free(*authtok);
2830 *authtok = NULL;
2831 } else {
2832 (void) strlcpy(*authtok, new_password,
2833 PASS_MAX+1);
2834 }
2835 break;
2836 default:
2837 __pam_log(LOG_AUTH | LOG_ERR,
2838 "__pam_get_authtok() invalid type: %d", type);
2839 error = PAM_SYMBOL_ERR;
2840 goto err_ret;
2841 }
2842 break;
2843 case PAM_PROMPT:
2844
2845 /*
2846 * Prompt for new password and save in pam handle item list
2847 * if the that item is not already set.
2848 */
2849
2850 (void) strncpy(messages[0], prompt, sizeof (messages[0]));
2851 if ((error = do_conv(pamh, PAM_PROMPT_ECHO_OFF, 1, messages,
2852 NULL, &ret_resp)) != PAM_SUCCESS)
2853 goto err_ret;
2854
2855 if (ret_resp->resp == NULL) {
2856 /* getpass didn't return anything */
2857 error = PAM_SYSTEM_ERR;
2858 goto err_ret;
2859 }
2860
2861 /* save the new password if this item was NULL */
2862 if (type) {
2863 if ((error = pam_get_item(pamh, type,
2864 (void **)&new_password)) != PAM_SUCCESS) {
2865 free_resp(1, ret_resp);
2866 goto err_ret;
2867 }
2868 if (new_password == NULL)
2869 (void) pam_set_item(pamh, type, ret_resp->resp);
2870 }
2871
2872 (void) strlcpy(*authtok, ret_resp->resp, PASS_MAX+1);
2873 free_resp(1, ret_resp);
2874 break;
2875 default:
2876 __pam_log(LOG_AUTH | LOG_ERR,
2877 "__pam_get_authtok() invalid source: %d", source);
2878 error = PAM_SYMBOL_ERR;
2879 goto err_ret;
2880 }
2881
2882 return (PAM_SUCCESS);
2883
2884 err_ret:
2885 bzero(*authtok, PASS_MAX+1);
2886 free(*authtok);
2887 *authtok = NULL;
2888 return (error);
2889 }
2890