root/nsswitch/winbind_nss_aix.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. logit
  2. free_pwd
  3. free_grp
  4. replace_commas
  5. decode_id
  6. decode_user
  7. fill_pwent
  8. fill_grent
  9. wb_aix_getgrgid
  10. wb_aix_getgrnam
  11. wb_aix_getgracct
  12. wb_aix_getgrset
  13. wb_aix_getpwuid
  14. wb_aix_getpwnam
  15. wb_aix_lsuser
  16. wb_aix_lsgroup
  17. pwd_to_group
  18. pwd_to_groupsids
  19. pwd_to_sid
  20. wb_aix_user_attrib
  21. wb_aix_group_attrib
  22. wb_aix_getentry
  23. wb_aix_open
  24. wb_aix_close
  25. wb_aix_attrlist
  26. wb_aix_normalize
  27. wb_aix_authenticate
  28. wb_aix_chpass
  29. wb_aix_passwdrestrictions
  30. wb_aix_passwdexpired
  31. wb_aix_getpasswd
  32. wb_aix_putentry
  33. wb_aix_commit
  34. wb_aix_getgrusers
  35. wb_aix_init

   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 
  56 static int debug_enabled;
  57 
  58 
  59 static void logit(const char *format, ...)
     /* [<][>][^][v][top][bottom][index][help] */
  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) \
  86 do { \
  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) \
  92 do { \
  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 */
  99 static void free_pwd(struct passwd *pwd)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 110 static void free_grp(struct group *grp)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 132 static void replace_commas(char *s)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 153 static unsigned decode_id(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 154 {
 155         unsigned id;
 156         sscanf(name+1, "%u", &id);
 157         return id;
 158 }
 159 
 160 static struct passwd *wb_aix_getpwuid(uid_t uid);
 161 
 162 static char *decode_user(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 186 static struct passwd *fill_pwent(struct winbindd_pw *pw)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 211 static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 268 static struct group *wb_aix_getgrgid(gid_t gid)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 296 static struct group *wb_aix_getgrnam(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 328 static struct group *wb_aix_getgracct(void *id, int type)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 343 static char *wb_aix_getgrset(char *user)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 398 static struct passwd *wb_aix_getpwuid(uid_t uid)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 427 static struct passwd *wb_aix_getpwnam(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 461 static int wb_aix_lsuser(char *attributes[], attrval_t results[], int size)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 509 static int wb_aix_lsgroup(char *attributes[], attrval_t results[], int size)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 554 static attrval_t pwd_to_group(struct passwd *pwd)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 570 static attrval_t pwd_to_groupsids(struct passwd *pwd)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 594 static attrval_t pwd_to_sid(struct passwd *pwd)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 616 static int wb_aix_user_attrib(const char *key, char *attributes[],
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 664 static int wb_aix_group_attrib(const char *key, char *attributes[],
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 698 static int wb_aix_getentry(char *key, char *table, char *attributes[],
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 733 static void *wb_aix_open(const char *name, const char *domain, int mode, char *options)
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 743 static void wb_aix_close(void *token)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 753 static attrlist_t **wb_aix_attrlist(void)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 830 static int wb_aix_normalize(char *longname, char *shortname)
     /* [<][>][^][v][top][bottom][index][help] */
 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  */
 860 static int wb_aix_authenticate(char *user, char *pass,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 909 static int wb_aix_chpass(char *user, char *oldpass, char *newpass, char **message)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 956 static int wb_aix_passwdrestrictions(char *user, char *newpass, char *oldpass,
     /* [<][>][^][v][top][bottom][index][help] */
 957                                      char **message)
 958 {
 959         logit("passwdresrictions called for '%s'\n", user);
 960         return 0;
 961 }
 962 
 963 
 964 static int wb_aix_passwdexpired(char *user, char **message)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 975 static char *wb_aix_getpasswd(char *user)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 986 static int wb_aix_putentry(char *key, char *table, char *attributes[],
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 995 static int wb_aix_commit(char *key, char *table)
     /* [<][>][^][v][top][bottom][index][help] */
 996 {
 997         logit("commit key='%s' table='%s'\n");
 998         errno = ENOSYS;
 999         return -1;
1000 }
1001 
1002 static int wb_aix_getgrusers(char *group, void *result, int type, int *size)
     /* [<][>][^][v][top][bottom][index][help] */
1003 {
1004         logit("getgrusers group='%s'\n", group);
1005         errno = ENOSYS;
1006         return -1;
1007 }
1008 
1009 
1010 #define DECL_METHOD(x) \
1011 int method_ ## x(void) \
1012 { \
1013         logit("UNIMPLEMENTED METHOD '%s'\n", #x); \
1014         errno = EINVAL; \
1015         return -1; \
1016 }
1017 
1018 #if LOG_UNIMPLEMENTED_CALLS
1019 DECL_METHOD(delgroup);
1020 DECL_METHOD(deluser);
1021 DECL_METHOD(newgroup);
1022 DECL_METHOD(newuser);
1023 DECL_METHOD(putgrent);
1024 DECL_METHOD(putgrusers);
1025 DECL_METHOD(putpwent);
1026 DECL_METHOD(lock);
1027 DECL_METHOD(unlock);
1028 DECL_METHOD(getcred);
1029 DECL_METHOD(setcred);
1030 DECL_METHOD(deletecred);
1031 #endif
1032 
1033 int wb_aix_init(struct secmethod_table *methods)
     /* [<][>][^][v][top][bottom][index][help] */
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 }

/* [<][>][^][v][top][bottom][index][help] */