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