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