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