1/* 2 Unix SMB/CIFS implementation. 3 4 AIX loadable authentication module, providing identification and 5 authentication routines against Samba winbind/Windows NT Domain 6 7 Copyright (C) Tim Potter 2003 8 Copyright (C) Steve Roylance 2003 9 Copyright (C) Andrew Tridgell 2003-2004 10 11 This library is free software; you can redistribute it and/or 12 modify it under the terms of the GNU Library General Public 13 License as published by the Free Software Foundation; either 14 version 2 of the License, or (at your option) any later version. 15 16 This library is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 Library General Public License for more details. 20 21 You should have received a copy of the GNU Library General Public 22 License along with this library; if not, write to the 23 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 24 Boston, MA 02111-1307, USA. 25*/ 26 27/* 28 29 To install this module copy nsswitch/WINBIND to /usr/lib/security and add 30 "WINBIND" in /usr/lib/security/methods.cfg and /etc/security/user 31 32 Note that this module also provides authentication and password 33 changing routines, so you do not need to install the winbind PAM 34 module. 35 36 see 37 http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixprggd/kernextc/sec_load_mod.htm 38 for some information in the interface that this module implements 39 40 Many thanks to Julianne Haugh for explaining some of the finer 41 details of this interface. 42 43 To debug this module use uess_test.c (which you can get from tridge) 44 or set "options=debug" in /usr/lib/security/methods.cfg 45 46*/ 47 48#include <stdlib.h> 49#include <string.h> 50#include <usersec.h> 51#include <errno.h> 52#include <stdarg.h> 53 54#include "winbind_client.h" 55 56#define WB_AIX_ENCODED '_' 57 58static int debug_enabled; 59 60 61static void logit(const char *format, ...) 62{ 63 va_list ap; 64 FILE *f; 65 if (!debug_enabled) { 66 return; 67 } 68 f = fopen("/tmp/WINBIND_DEBUG.log", "a"); 69 if (!f) return; 70 va_start(ap, format); 71 vfprintf(f, format, ap); 72 va_end(ap); 73 fclose(f); 74} 75 76 77#define HANDLE_ERRORS(ret) do { \ 78 if ((ret) == NSS_STATUS_NOTFOUND) { \ 79 errno = ENOENT; \ 80 return NULL; \ 81 } else if ((ret) != NSS_STATUS_SUCCESS) { \ 82 errno = EIO; \ 83 return NULL; \ 84 } \ 85} while (0) 86 87#define STRCPY_RET(dest, src) \ 88do { \ 89 if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return -1; } \ 90 strcpy(dest, src); \ 91} while (0) 92 93#define STRCPY_RETNULL(dest, src) \ 94do { \ 95 if (strlen(src)+1 > sizeof(dest)) { errno = EINVAL; return NULL; } \ 96 strcpy(dest, src); \ 97} while (0) 98 99 100/* free a passwd structure */ 101static void free_pwd(struct passwd *pwd) 102{ 103 free(pwd->pw_name); 104 free(pwd->pw_passwd); 105 free(pwd->pw_gecos); 106 free(pwd->pw_dir); 107 free(pwd->pw_shell); 108 free(pwd); 109} 110 111/* free a group structure */ 112static void free_grp(struct group *grp) 113{ 114 int i; 115 116 free(grp->gr_name); 117 free(grp->gr_passwd); 118 119 if (!grp->gr_mem) { 120 free(grp); 121 return; 122 } 123 124 for (i=0; grp->gr_mem[i]; i++) { 125 free(grp->gr_mem[i]); 126 } 127 128 free(grp->gr_mem); 129 free(grp); 130} 131 132 133/* replace commas with nulls, and null terminate */ 134static void replace_commas(char *s) 135{ 136 char *p, *p0=s; 137 for (p=strchr(s, ','); p; p = strchr(p+1, ',')) { 138 *p=0; 139 p0 = p+1; 140 } 141 142 p0[strlen(p0)+1] = 0; 143} 144 145 146/* the decode_*() routines are used to cope with the fact that AIX 5.2 147 and below cannot handle user or group names longer than 8 148 characters in some interfaces. We use the normalize method to 149 provide a mapping to a username that fits, by using the form '_UID' 150 or '_GID'. 151 152 this only works if you can guarantee that the WB_AIX_ENCODED char 153 is not used as the first char of any other username 154*/ 155static unsigned decode_id(const char *name) 156{ 157 unsigned id; 158 sscanf(name+1, "%u", &id); 159 return id; 160} 161 162static struct passwd *wb_aix_getpwuid(uid_t uid); 163 164static char *decode_user(const char *name) 165{ 166 struct passwd *pwd; 167 unsigned id; 168 char *ret; 169 170 sscanf(name+1, "%u", &id); 171 pwd = wb_aix_getpwuid(id); 172 if (!pwd) { 173 return NULL; 174 } 175 ret = strdup(pwd->pw_name); 176 177 free_pwd(pwd); 178 179 logit("decoded '%s' -> '%s'\n", name, ret); 180 181 return ret; 182} 183 184 185/* 186 fill a struct passwd from a winbindd_pw struct, allocating as a single block 187*/ 188static struct passwd *fill_pwent(struct winbindd_pw *pw) 189{ 190 struct passwd *result; 191 192 result = calloc(1, sizeof(struct passwd)); 193 if (!result) { 194 errno = ENOMEM; 195 return NULL; 196 } 197 198 result->pw_uid = pw->pw_uid; 199 result->pw_gid = pw->pw_gid; 200 result->pw_name = strdup(pw->pw_name); 201 result->pw_passwd = strdup(pw->pw_passwd); 202 result->pw_gecos = strdup(pw->pw_gecos); 203 result->pw_dir = strdup(pw->pw_dir); 204 result->pw_shell = strdup(pw->pw_shell); 205 206 return result; 207} 208 209 210/* 211 fill a struct group from a winbindd_pw struct, allocating as a single block 212*/ 213static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem) 214{ 215 int i; 216 struct group *result; 217 char *p, *name; 218 219 result = calloc(1, sizeof(struct group)); 220 if (!result) { 221 errno = ENOMEM; 222 return NULL; 223 } 224 225 result->gr_gid = gr->gr_gid; 226 227 result->gr_name = strdup(gr->gr_name); 228 result->gr_passwd = strdup(gr->gr_passwd); 229 230 /* Group membership */ 231 if ((gr->num_gr_mem < 0) || !gr_mem) { 232 gr->num_gr_mem = 0; 233 } 234 235 if (gr->num_gr_mem == 0) { 236 /* Group is empty */ 237 return result; 238 } 239 240 result->gr_mem = (char **)malloc(sizeof(char *) * (gr->num_gr_mem+1)); 241 if (!result->gr_mem) { 242 errno = ENOMEM; 243 return NULL; 244 } 245 246 /* Start looking at extra data */ 247 i=0; 248 for (name = strtok_r(gr_mem, ",", &p); 249 name; 250 name = strtok_r(NULL, ",", &p)) { 251 if (i == gr->num_gr_mem) { 252 break; 253 } 254 result->gr_mem[i] = strdup(name); 255 i++; 256 } 257 258 /* Terminate list */ 259 result->gr_mem[i] = NULL; 260 261 return result; 262} 263 264 265 266/* take a group id and return a filled struct group */ 267static struct group *wb_aix_getgrgid(gid_t gid) 268{ 269 struct winbindd_response response; 270 struct winbindd_request request; 271 struct group *grp; 272 NSS_STATUS ret; 273 274 logit("getgrgid %d\n", gid); 275 276 ZERO_STRUCT(response); 277 ZERO_STRUCT(request); 278 279 request.data.gid = gid; 280 281 ret = winbindd_request(WINBINDD_GETGRGID, &request, &response); 282 283 logit("getgrgid ret=%d\n", ret); 284 285 HANDLE_ERRORS(ret); 286 287 grp = fill_grent(&response.data.gr, response.extra_data); 288 289 free_response(&response); 290 291 return grp; 292} 293 294/* take a group name and return a filled struct group */ 295static struct group *wb_aix_getgrnam(const char *name) 296{ 297 struct winbindd_response response; 298 struct winbindd_request request; 299 NSS_STATUS ret; 300 struct group *grp; 301 302 if (*name == WB_AIX_ENCODED) { 303 return wb_aix_getgrgid(decode_id(name)); 304 } 305 306 logit("getgrnam '%s'\n", name); 307 308 ZERO_STRUCT(response); 309 ZERO_STRUCT(request); 310 311 STRCPY_RETNULL(request.data.groupname, name); 312 313 ret = winbindd_request(WINBINDD_GETGRNAM, &request, &response); 314 315 HANDLE_ERRORS(ret); 316 317 grp = fill_grent(&response.data.gr, response.extra_data); 318 319 free_response(&response); 320 321 return grp; 322} 323 324 325/* this call doesn't have to fill in the gr_mem, but we do anyway 326 for simplicity */ 327static struct group *wb_aix_getgracct(void *id, int type) 328{ 329 if (type == 1) { 330 return wb_aix_getgrnam((char *)id); 331 } 332 if (type == 0) { 333 return wb_aix_getgrgid(*(int *)id); 334 } 335 errno = EINVAL; 336 return NULL; 337} 338 339 340/* take a username and return a string containing a comma-separated 341 list of group id numbers to which the user belongs */ 342static char *wb_aix_getgrset(char *user) 343{ 344 struct winbindd_response response; 345 struct winbindd_request request; 346 NSS_STATUS ret; 347 int i, idx; 348 char *tmpbuf; 349 int num_gids; 350 gid_t *gid_list; 351 char *r_user = user; 352 353 if (*user == WB_AIX_ENCODED) { 354 r_user = decode_user(r_user); 355 if (!r_user) { 356 errno = ENOENT; 357 return NULL; 358 } 359 } 360 361 logit("getgrset '%s'\n", r_user); 362 363 STRCPY_RETNULL(request.data.username, r_user); 364 365 if (*user == WB_AIX_ENCODED) { 366 free(r_user); 367 } 368 369 ret = winbindd_request(WINBINDD_GETGROUPS, &request, &response); 370 371 HANDLE_ERRORS(ret); 372 373 num_gids = response.data.num_entries; 374 gid_list = (gid_t *)response.extra_data; 375 376 /* allocate a space large enough to contruct the string */ 377 tmpbuf = malloc(num_gids*12); 378 if (!tmpbuf) { 379 return NULL; 380 } 381 382 for (idx=i=0; i < num_gids-1; i++) { 383 idx += sprintf(tmpbuf+idx, "%u,", gid_list[i]); 384 } 385 idx += sprintf(tmpbuf+idx, "%u", gid_list[i]); 386 387 free_response(&response); 388 389 return tmpbuf; 390} 391 392 393/* take a uid and return a filled struct passwd */ 394static struct passwd *wb_aix_getpwuid(uid_t uid) 395{ 396 struct winbindd_response response; 397 struct winbindd_request request; 398 NSS_STATUS ret; 399 struct passwd *pwd; 400 401 logit("getpwuid '%d'\n", uid); 402 403 ZERO_STRUCT(response); 404 ZERO_STRUCT(request); 405 406 request.data.uid = uid; 407 408 ret = winbindd_request(WINBINDD_GETPWUID, &request, &response); 409 410 HANDLE_ERRORS(ret); 411 412 pwd = fill_pwent(&response.data.pw); 413 414 free_response(&response); 415 416 logit("getpwuid gave ptr %p\n", pwd); 417 418 return pwd; 419} 420 421 422/* take a username and return a filled struct passwd */ 423static struct passwd *wb_aix_getpwnam(const char *name) 424{ 425 struct winbindd_response response; 426 struct winbindd_request request; 427 NSS_STATUS ret; 428 struct passwd *pwd; 429 430 if (*name == WB_AIX_ENCODED) { 431 return wb_aix_getpwuid(decode_id(name)); 432 } 433 434 logit("getpwnam '%s'\n", name); 435 436 ZERO_STRUCT(response); 437 ZERO_STRUCT(request); 438 439 STRCPY_RETNULL(request.data.username, name); 440 441 ret = winbindd_request(WINBINDD_GETPWNAM, &request, &response); 442 443 HANDLE_ERRORS(ret); 444 445 pwd = fill_pwent(&response.data.pw); 446 447 free_response(&response); 448 449 logit("getpwnam gave ptr %p\n", pwd); 450 451 return pwd; 452} 453 454/* 455 list users 456*/ 457static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size) 458{ 459 NSS_STATUS ret; 460 struct winbindd_request request; 461 struct winbindd_response response; 462 int len; 463 char *s; 464 465 if (size != 1 || strcmp(attributes[0], S_USERS) != 0) { 466 logit("invalid lsuser op\n"); 467 errno = EINVAL; 468 return -1; 469 } 470 471 ZERO_STRUCT(request); 472 ZERO_STRUCT(response); 473 474 ret = winbindd_request(WINBINDD_LIST_USERS, &request, &response); 475 if (ret != 0) { 476 errno = EINVAL; 477 return -1; 478 } 479 480 len = strlen(response.extra_data); 481 482 s = malloc(len+2); 483 if (!s) { 484 free_response(&response); 485 errno = ENOMEM; 486 return -1; 487 } 488 489 memcpy(s, response.extra_data, len+1); 490 491 replace_commas(s); 492 493 results[0].attr_un.au_char = s; 494 results[0].attr_flag = 0; 495 496 free_response(&response); 497 498 return 0; 499} 500 501 502/* 503 list groups 504*/ 505static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size) 506{ 507 NSS_STATUS ret; 508 struct winbindd_request request; 509 struct winbindd_response response; 510 int len; 511 char *s; 512 513 if (size != 1 || strcmp(attributes[0], S_GROUPS) != 0) { 514 logit("invalid lsgroup op\n"); 515 errno = EINVAL; 516 return -1; 517 } 518 519 ZERO_STRUCT(request); 520 ZERO_STRUCT(response); 521 522 ret = winbindd_request(WINBINDD_LIST_GROUPS, &request, &response); 523 if (ret != 0) { 524 errno = EINVAL; 525 return -1; 526 } 527 528 len = strlen(response.extra_data); 529 530 s = malloc(len+2); 531 if (!s) { 532 free_response(&response); 533 errno = ENOMEM; 534 return -1; 535 } 536 537 memcpy(s, response.extra_data, len+1); 538 539 replace_commas(s); 540 541 results[0].attr_un.au_char = s; 542 results[0].attr_flag = 0; 543 544 free_response(&response); 545 546 return 0; 547} 548 549 550static attrval_t pwd_to_group(struct passwd *pwd) 551{ 552 attrval_t r; 553 struct group *grp = wb_aix_getgrgid(pwd->pw_gid); 554 555 if (!grp) { 556 r.attr_flag = EINVAL; 557 } else { 558 r.attr_flag = 0; 559 r.attr_un.au_char = strdup(grp->gr_name); 560 free_grp(grp); 561 } 562 563 return r; 564} 565 566static attrval_t pwd_to_groupsids(struct passwd *pwd) 567{ 568 attrval_t r; 569 char *s, *p; 570 571 s = wb_aix_getgrset(pwd->pw_name); 572 if (!s) { 573 r.attr_flag = EINVAL; 574 return r; 575 } 576 577 p = malloc(strlen(s)+2); 578 if (!p) { 579 r.attr_flag = ENOMEM; 580 return r; 581 } 582 583 strcpy(p, s); 584 replace_commas(p); 585 free(s); 586 587 r.attr_un.au_char = p; 588 589 return r; 590} 591 592static attrval_t pwd_to_sid(struct passwd *pwd) 593{ 594 struct winbindd_request request; 595 struct winbindd_response response; 596 attrval_t r; 597 598 ZERO_STRUCT(request); 599 ZERO_STRUCT(response); 600 601 request.data.uid = pwd->pw_uid; 602 603 if (winbindd_request(WINBINDD_UID_TO_SID, &request, &response) != 604 NSS_STATUS_SUCCESS) { 605 r.attr_flag = ENOENT; 606 } else { 607 r.attr_flag = 0; 608 r.attr_un.au_char = strdup(response.data.sid.sid); 609 } 610 611 return r; 612} 613 614static int wb_aix_user_attrib(const char *key, char *attributes[], 615 attrval_t results[], int size) 616{ 617 struct passwd *pwd; 618 int i; 619 620 pwd = wb_aix_getpwnam(key); 621 if (!pwd) { 622 errno = ENOENT; 623 return -1; 624 } 625 626 for (i=0;i<size;i++) { 627 results[i].attr_flag = 0; 628 629 if (strcmp(attributes[i], S_ID) == 0) { 630 results[i].attr_un.au_int = pwd->pw_uid; 631 } else if (strcmp(attributes[i], S_PWD) == 0) { 632 results[i].attr_un.au_char = strdup(pwd->pw_passwd); 633 } else if (strcmp(attributes[i], S_HOME) == 0) { 634 results[i].attr_un.au_char = strdup(pwd->pw_dir); 635 } else if (strcmp(attributes[0], S_SHELL) == 0) { 636 results[i].attr_un.au_char = strdup(pwd->pw_shell); 637 } else if (strcmp(attributes[0], S_REGISTRY) == 0) { 638 results[i].attr_un.au_char = strdup("WINBIND"); 639 } else if (strcmp(attributes[0], S_GECOS) == 0) { 640 results[i].attr_un.au_char = strdup(pwd->pw_gecos); 641 } else if (strcmp(attributes[0], S_PGRP) == 0) { 642 results[i] = pwd_to_group(pwd); 643 } else if (strcmp(attributes[0], S_GECOS) == 0) { 644 results[i].attr_un.au_char = strdup(pwd->pw_gecos); 645 } else if (strcmp(attributes[0], S_GROUPSIDS) == 0) { 646 results[i] = pwd_to_groupsids(pwd); 647 } else if (strcmp(attributes[0], "SID") == 0) { 648 results[i] = pwd_to_sid(pwd); 649 } else { 650 logit("Unknown user attribute '%s'\n", attributes[i]); 651 results[i].attr_flag = EINVAL; 652 } 653 } 654 655 free_pwd(pwd); 656 657 return 0; 658} 659 660static int wb_aix_group_attrib(const char *key, char *attributes[], 661 attrval_t results[], int size) 662{ 663 struct group *grp; 664 int i; 665 666 grp = wb_aix_getgrnam(key); 667 if (!grp) { 668 errno = ENOENT; 669 return -1; 670 } 671 672 for (i=0;i<size;i++) { 673 results[i].attr_flag = 0; 674 675 if (strcmp(attributes[i], S_PWD) == 0) { 676 results[i].attr_un.au_char = strdup(grp->gr_passwd); 677 } else if (strcmp(attributes[i], S_ID) == 0) { 678 results[i].attr_un.au_int = grp->gr_gid; 679 } else { 680 logit("Unknown group attribute '%s'\n", attributes[i]); 681 results[i].attr_flag = EINVAL; 682 } 683 } 684 685 free_grp(grp); 686 687 return 0; 688} 689 690 691/* 692 called for user/group enumerations 693*/ 694static int wb_aix_getentry(char *key, char *table, char *attributes[], 695 attrval_t results[], int size) 696{ 697 logit("Got getentry with key='%s' table='%s' size=%d attributes[0]='%s'\n", 698 key, table, size, attributes[0]); 699 700 if (strcmp(key, "ALL") == 0 && 701 strcmp(table, "user") == 0) { 702 return wb_aix_lsuser(attributes, results, size); 703 } 704 705 if (strcmp(key, "ALL") == 0 && 706 strcmp(table, "group") == 0) { 707 return wb_aix_lsgroup(attributes, results, size); 708 } 709 710 if (strcmp(table, "user") == 0) { 711 return wb_aix_user_attrib(key, attributes, results, size); 712 } 713 714 if (strcmp(table, "group") == 0) { 715 return wb_aix_group_attrib(key, attributes, results, size); 716 } 717 718 logit("Unknown getentry operation key='%s' table='%s'\n", key, table); 719 720 errno = ENOSYS; 721 return -1; 722} 723 724 725 726/* 727 called to start the backend 728*/ 729static void *wb_aix_open(const char *name, const char *domain, int mode, char *options) 730{ 731 if (strstr(options, "debug")) { 732 debug_enabled = 1; 733 } 734 logit("open name='%s' mode=%d domain='%s' options='%s'\n", name, domain, 735 mode, options); 736 return NULL; 737} 738 739static void wb_aix_close(void *token) 740{ 741 logit("close\n"); 742 return; 743} 744 745#ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST 746/* 747 return a list of additional attributes supported by the backend 748*/ 749static attrlist_t **wb_aix_attrlist(void) 750{ 751 attrlist_t **ret; 752 logit("method attrlist called\n"); 753 ret = malloc(2*sizeof(attrlist_t *) + sizeof(attrlist_t)); 754 if (!ret) { 755 errno = ENOMEM; 756 return NULL; 757 } 758 759 ret[0] = (attrlist_t *)(ret+2); 760 761 /* just one extra attribute - the windows SID */ 762 ret[0]->al_name = strdup("SID"); 763 ret[0]->al_flags = AL_USERATTR; 764 ret[0]->al_type = SEC_CHAR; 765 ret[1] = NULL; 766 767 return ret; 768} 769#endif 770 771 772/* 773 turn a long username into a short one. Needed to cope with the 8 char 774 username limit in AIX 5.2 and below 775*/ 776static int wb_aix_normalize(char *longname, char *shortname) 777{ 778 struct passwd *pwd; 779 780 logit("normalize '%s'\n", longname); 781 782 /* automatically cope with AIX 5.3 with longer usernames 783 when it comes out */ 784 if (S_NAMELEN > strlen(longname)) { 785 strcpy(shortname, longname); 786 return 1; 787 } 788 789 pwd = wb_aix_getpwnam(longname); 790 if (!pwd) { 791 errno = ENOENT; 792 return 0; 793 } 794 795 sprintf(shortname, "%c%07u", WB_AIX_ENCODED, pwd->pw_uid); 796 797 free_pwd(pwd); 798 799 return 1; 800} 801 802 803/* 804 authenticate a user 805 */ 806static int wb_aix_authenticate(char *user, char *pass, 807 int *reenter, char **message) 808{ 809 struct winbindd_request request; 810 struct winbindd_response response; 811 NSS_STATUS result; 812 char *r_user = user; 813 814 logit("authenticate '%s' response='%s'\n", user, pass); 815 816 *reenter = 0; 817 *message = NULL; 818 819 /* Send off request */ 820 ZERO_STRUCT(request); 821 ZERO_STRUCT(response); 822 823 if (*user == WB_AIX_ENCODED) { 824 r_user = decode_user(r_user); 825 if (!r_user) { 826 return AUTH_NOTFOUND; 827 } 828 } 829 830 STRCPY_RET(request.data.auth.user, r_user); 831 STRCPY_RET(request.data.auth.pass, pass); 832 833 if (*user == WB_AIX_ENCODED) { 834 free(r_user); 835 } 836 837 result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response); 838 839 free_response(&response); 840 841 logit("auth result %d for '%s'\n", result, user); 842 843 if (result == NSS_STATUS_SUCCESS) { 844 errno = 0; 845 return AUTH_SUCCESS; 846 } 847 848 return AUTH_FAILURE; 849} 850 851 852/* 853 change a user password 854*/ 855static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message) 856{ 857 struct winbindd_request request; 858 struct winbindd_response response; 859 NSS_STATUS result; 860 char *r_user = user; 861 862 if (*user == WB_AIX_ENCODED) { 863 r_user = decode_user(r_user); 864 if (!r_user) { 865 errno = ENOENT; 866 return -1; 867 } 868 } 869 870 logit("chpass '%s' old='%s' new='%s'\n", r_user, oldpass, newpass); 871 872 *message = NULL; 873 874 /* Send off request */ 875 ZERO_STRUCT(request); 876 ZERO_STRUCT(response); 877 878 STRCPY_RET(request.data.chauthtok.user, r_user); 879 STRCPY_RET(request.data.chauthtok.oldpass, oldpass); 880 STRCPY_RET(request.data.chauthtok.newpass, newpass); 881 882 if (*user == WB_AIX_ENCODED) { 883 free(r_user); 884 } 885 886 result = winbindd_request(WINBINDD_PAM_CHAUTHTOK, &request, &response); 887 888 free_response(&response); 889 890 if (result == NSS_STATUS_SUCCESS) { 891 errno = 0; 892 return 0; 893 } 894 895 errno = EINVAL; 896 return -1; 897} 898 899/* 900 don't do any password strength testing for now 901*/ 902static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass, 903 char **message) 904{ 905 logit("passwdresrictions called for '%s'\n", user); 906 return 0; 907} 908 909 910static int wb_aix_passwdexpired(char *user, char **message) 911{ 912 logit("passwdexpired '%s'\n", user); 913 /* we should check the account bits here */ 914 return 0; 915} 916 917 918/* 919 we can't return a crypt() password 920*/ 921static char *wb_aix_getpasswd(char *user) 922{ 923 logit("getpasswd '%s'\n", user); 924 errno = ENOSYS; 925 return NULL; 926} 927 928/* 929 this is called to update things like the last login time. We don't 930 currently pass this onto the DC 931*/ 932static int wb_aix_putentry(char *key, char *table, char *attributes[], 933 attrval_t values[], int size) 934{ 935 logit("putentry key='%s' table='%s' attrib='%s'\n", 936 key, table, size>=1?attributes[0]:"<null>"); 937 errno = ENOSYS; 938 return -1; 939} 940 941static int wb_aix_commit(char *key, char *table) 942{ 943 logit("commit key='%s' table='%s'\n"); 944 errno = ENOSYS; 945 return -1; 946} 947 948static int wb_aix_getgrusers(char *group, void *result, int type, int *size) 949{ 950 logit("getgrusers group='%s'\n", group); 951 errno = ENOSYS; 952 return -1; 953} 954 955 956#define DECL_METHOD(x) \ 957int method_ ## x(void) \ 958{ \ 959 logit("UNIMPLEMENTED METHOD '%s'\n", #x); \ 960 errno = EINVAL; \ 961 return -1; \ 962} 963 964#if LOG_UNIMPLEMENTED_CALLS 965DECL_METHOD(delgroup); 966DECL_METHOD(deluser); 967DECL_METHOD(newgroup); 968DECL_METHOD(newuser); 969DECL_METHOD(putgrent); 970DECL_METHOD(putgrusers); 971DECL_METHOD(putpwent); 972DECL_METHOD(lock); 973DECL_METHOD(unlock); 974DECL_METHOD(getcred); 975DECL_METHOD(setcred); 976DECL_METHOD(deletecred); 977#endif 978 979int wb_aix_init(struct secmethod_table *methods) 980{ 981 ZERO_STRUCTP(methods); 982 983#ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_VERSION 984 methods->method_version = SECMETHOD_VERSION_520; 985#endif 986 987 methods->method_getgrgid = wb_aix_getgrgid; 988 methods->method_getgrnam = wb_aix_getgrnam; 989 methods->method_getgrset = wb_aix_getgrset; 990 methods->method_getpwnam = wb_aix_getpwnam; 991 methods->method_getpwuid = wb_aix_getpwuid; 992 methods->method_getentry = wb_aix_getentry; 993 methods->method_open = wb_aix_open; 994 methods->method_close = wb_aix_close; 995 methods->method_normalize = wb_aix_normalize; 996 methods->method_passwdexpired = wb_aix_passwdexpired; 997 methods->method_putentry = wb_aix_putentry; 998 methods->method_getpasswd = wb_aix_getpasswd; 999 methods->method_authenticate = wb_aix_authenticate; 1000 methods->method_commit = wb_aix_commit; 1001 methods->method_chpass = wb_aix_chpass; 1002 methods->method_passwdrestrictions = wb_aix_passwdrestrictions; 1003 methods->method_getgracct = wb_aix_getgracct; 1004 methods->method_getgrusers = wb_aix_getgrusers; 1005#ifdef HAVE_STRUCT_SECMETHOD_TABLE_METHOD_ATTRLIST 1006 methods->method_attrlist = wb_aix_attrlist; 1007#endif 1008 1009#if LOG_UNIMPLEMENTED_CALLS 1010 methods->method_delgroup = method_delgroup; 1011 methods->method_deluser = method_deluser; 1012 methods->method_newgroup = method_newgroup; 1013 methods->method_newuser = method_newuser; 1014 methods->method_putgrent = method_putgrent; 1015 methods->method_putgrusers = method_putgrusers; 1016 methods->method_putpwent = method_putpwent; 1017 methods->method_lock = method_lock; 1018 methods->method_unlock = method_unlock; 1019 methods->method_getcred = method_getcred; 1020 methods->method_setcred = method_setcred; 1021 methods->method_deletecred = method_deletecred; 1022#endif 1023 1024 return AUTH_SUCCESS; 1025} 1026 1027