/* Unix SMB/CIFS implementation. AIX loadable authentication module, providing identification routines against Samba winbind/Windows NT Domain Copyright (C) Tim Potter 2003 Copyright (C) Steve Roylance 2003 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "winbind_client.h" #define MAX_GETPWENT_USERS 250 #define MAX_GETGRENT_USERS 250 static struct passwd *fill_pwent(struct winbindd_pw *pw) { struct passwd *result; if (!(result = malloc(sizeof(struct passwd)))) goto out; ZERO_STRUCTP(result); /* User name */ if ((result->pw_name = malloc(strlen(pw->pw_name) + 1)) == NULL) goto out; strcpy(result->pw_name, pw->pw_name); /* Password */ if ((result->pw_passwd = malloc(strlen(pw->pw_passwd) + 1)) == NULL) goto out; strcpy(result->pw_passwd, pw->pw_passwd); /* [ug]id */ result->pw_uid = pw->pw_uid; result->pw_gid = pw->pw_gid; /* GECOS */ if ((result->pw_gecos = malloc(strlen(pw->pw_gecos) + 1)) == NULL) goto out; strcpy(result->pw_gecos, pw->pw_gecos); /* Home directory */ if ((result->pw_dir = malloc(strlen(pw->pw_dir) + 1)) == NULL) goto out; strcpy(result->pw_dir, pw->pw_dir); /* Logon shell */ if ((result->pw_shell = malloc(strlen(pw->pw_shell) + 1)) == NULL) goto out; strcpy(result->pw_shell, pw->pw_shell); return result; /* A memory allocation failed, undo succesfull allocations and return NULL */ out: errno = ENOMEM; SAFE_FREE(result->pw_dir); SAFE_FREE(result->pw_gecos); SAFE_FREE(result->pw_passwd); SAFE_FREE(result->pw_name); SAFE_FREE(result); return NULL; } static BOOL next_token(char **ptr,char *buff,char *sep, size_t bufsize) { char *s; BOOL quoted; size_t len=1; if (!ptr) return(False); s = *ptr; /* default to simple separators */ if (!sep) sep = " \t\n\r"; /* find the first non sep char */ while (*s && strchr(sep,*s)) s++; /* nothing left? */ if (! *s) return(False); /* copy over the token */ for (quoted = False; len < bufsize && *s && (quoted || !strchr(sep,*s)); s++) { if (*s == '\"') { quoted = !quoted; } else { len++; *buff++ = *s; } } *ptr = (*s) ? s+1 : s; *buff = 0; return(True); } static struct group *fill_grent(struct winbindd_gr *gr, char *gr_mem) { fstring name; int i; char *tst; struct group *result; if (!(result = malloc(sizeof(struct group)))) goto out; ZERO_STRUCTP(result); /* Group name */ if ((result->gr_name = malloc(strlen(gr->gr_name) + 1)) == NULL) goto out; strcpy(result->gr_name, gr->gr_name); /* Password */ if ((result->gr_passwd = malloc(strlen(gr->gr_passwd) + 1)) == NULL) goto out; strcpy(result->gr_passwd, gr->gr_passwd); /* gid */ result->gr_gid = gr->gr_gid; /* Group membership */ if ((gr->num_gr_mem < 0) || !gr_mem) { gr->num_gr_mem = 0; } if (gr->num_gr_mem == 0) { /* Group is empty */ *(result->gr_mem) = NULL; return result; } if ((tst = malloc(((gr->num_gr_mem + 1) * sizeof(char *)))) == NULL) goto out; result->gr_mem = (char **)tst; /* Start looking at extra data */ i = 0; while(next_token((char **)&gr_mem, name, ",", sizeof(fstring))) { /* Allocate space for member */ if (((result->gr_mem)[i] = malloc(strlen(name) + 1)) == NULL) { for ( i -= 1; i >= 0; i--) SAFE_FREE((result->gr_mem)[i]); goto out; } strcpy((result->gr_mem)[i], name); i++; } /* Terminate list */ (result->gr_mem)[i] = NULL; return result; /* A memory allocation failed, undo succesfull allocations and return NULL */ out: errno = ENOMEM; SAFE_FREE(tst); SAFE_FREE(result->gr_passwd); SAFE_FREE(result->gr_name); SAFE_FREE(result); return NULL; } static struct group * wb_aix_getgrgid (gid_t gid) { /* take a group id and return a filled struct group */ struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; ZERO_STRUCT(response); ZERO_STRUCT(request); request.data.gid = gid; ret = winbindd_request(WINBINDD_GETGRGID, &request, &response); if (ret == NSS_STATUS_SUCCESS) { return fill_grent(&response.data.gr, response.extra_data); } else if (ret == NSS_STATUS_NOTFOUND) { errno = ENOENT; } else { errno = EIO; } return NULL; } static struct group * wb_aix_getgrnam (const char *name) { /* take a group name and return a filled struct group */ struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; ZERO_STRUCT(response); ZERO_STRUCT(request); strncpy(request.data.groupname, name, sizeof(request.data.groupname)); request.data.groupname [sizeof(request.data.groupname) - 1] = '\0'; ret = winbindd_request(WINBINDD_GETGRNAM, &request, &response); if (ret == NSS_STATUS_SUCCESS) { return fill_grent(&response.data.gr, response.extra_data); } else if (ret == NSS_STATUS_NOTFOUND) { errno = ENOENT; } else { errno = EIO; } return NULL; } static char * wb_aix_getgrset (const char *user) { /* take a username and return a string containing a comma-separated list of group id numbers to which the user belongs */ struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; strncpy(request.data.username, user, sizeof(request.data.username) - 1); request.data.username [sizeof(request.data.username) - 1] = '\0'; ret = winbindd_request(WINBINDD_GETGROUPS, &request, &response); if (ret == NSS_STATUS_SUCCESS ) { int i, idx = 0; char *tmpbuf, *result; int num_gids = response.data.num_entries; gid_t *gid_list = (gid_t *)response.extra_data; /* allocate a space large enough to contruct the string */ if (!(tmpbuf = malloc(num_gids*12))) { errno = ENOMEM; return NULL; } idx += sprintf(tmpbuf, "%d", gid_list[0]); for (i = 1; i < num_gids; i++) { tmpbuf[idx++] = ','; idx += sprintf(tmpbuf+idx, "%d", gid_list[i]); } tmpbuf[idx] = '\0'; if (!(result = malloc(idx+1))) { /* allocate a string the right size to return, but if that fails may as well return our working buffer because it contains the same thing */ return tmpbuf; } strcpy(result, tmpbuf); SAFE_FREE(tmpbuf); return result; } else if (ret == NSS_STATUS_NOTFOUND) { errno = ENOENT; } else { errno = EIO; } return NULL; } static struct passwd * wb_aix_getpwuid (uid_t uid) { /* take a uid and return a filled struct passwd */ struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; ZERO_STRUCT(response); ZERO_STRUCT(request); request.data.uid = uid; ret = winbindd_request(WINBINDD_GETPWUID, &request, &response); if (ret == NSS_STATUS_SUCCESS) { return fill_pwent(&response.data.pw); } else if (ret == NSS_STATUS_NOTFOUND ) { errno = ENOENT; } else { errno = EIO; } return NULL; } static struct passwd * wb_aix_getpwnam (const char *name) { /* take a username and return a filled struct passwd */ struct winbindd_response response; struct winbindd_request request; NSS_STATUS ret; ZERO_STRUCT(response); ZERO_STRUCT(request); strncpy(request.data.username, name, sizeof(request.data.username) - 1); request.data.username [sizeof(request.data.username) - 1] = '\0'; ret = winbindd_request(WINBINDD_GETPWNAM, &request, &response); if (ret == NSS_STATUS_SUCCESS ) { return fill_pwent(&response.data.pw); } else if (ret == NSS_STATUS_NOTFOUND) { errno = ENOENT; } else { errno = EIO; } return NULL; } int wb_aix_init (struct secmethod_table *methods) { memset(methods, 0, sizeof(*methods)); /* identification methods, this is the minimum requried for a working module */ methods->method_getgrgid = wb_aix_getgrgid; methods->method_getgrnam = wb_aix_getgrnam; methods->method_getgrset = wb_aix_getgrset; methods->method_getpwnam = wb_aix_getpwnam; methods->method_getpwuid = wb_aix_getpwuid; return AUTH_SUCCESS; }