/* * @(#)nss_pool 1.0 David Groep * * Provide nameservice for the pw database based on the current mappings * contained in the $GRIDMAPDIR directory * * (C) David Groep and NIKHEF, 2004 Limited liabilities apply. * */ #include #include #include #include #include #include #include #include #include #include #include "config.h" #define MAXNAMELEN 2048 #define PWLINELEN 512 #define CHUNKSIZE 64 #define NSSPOOL_UNDEF -1 #define NSSPOOL_INIT -2 #ifndef NSSPOOL_STATIC_GMDIR #define NSSPOOL_STATIC_GMDIR NULL #endif /* ! NSSPOOL_STATIC_GMDIR */ #ifndef NSSPOOL_STATIC_GMINFO #define NSSPOOL_STATIC_GMINFO NULL #endif /* ! NSSPOOL_STATIC_GMINFO */ #define NSSPOOL_ENV_GRIDMAPDIR "GRIDMAPDIR" #define NSSPOOL_ENV_GRIDMAPINFO "GRIDMAPINFO" typedef struct pamap_ent { ino_t ino; char *commonname; char *uidname; long uid; gid_t gid; char *homedir; char *shell; } pamap_ent_t; static pamap_ent_t *pamap = NULL; static int pamap_size = -1; static uid_t pending_uids[32]; static int pending_uids_max = -1; static int uidlock=0; static int getpwent_idx=-1; enum nss_status _nss_pool_setpwent (void); enum nss_status _nss_pool_endpwent (void); enum nss_status _nss_pool_getpwent_r (struct passwd *result, char *buffer, size_t buflen); enum nss_status _nss_pool_getpwnam_r (const char *name, struct passwd *result, char *buffer, size_t buflen); enum nss_status _nss_pool_getpwuid_r (uid_t uid, struct passwd *result, char *buffer, size_t buflen); int nss_pool_addlockuid( const uid_t uid ) { int i; /* very crude sem */ while(uidlock) usleep(10); uidlock++; for(i=0;i<=pending_uids_max;i++) { if(pending_uids[i]==uid) break; } if(pending_uids_max<0 || pending_uids[i]!=uid) { /* find empty slot to insert */ if(pending_uids_max<0) { pending_uids[0]=uid; pending_uids_max=0; } else { for(i=0;i<=pending_uids_max;i++) { if(pending_uids[i]==-1) break; } if(pending_uids[i]==-1) { pending_uids[i]=uid; } else { pending_uids[pending_uids_max]=uid; pending_uids_max++; } } } uidlock--; return 0; } int nss_pool_islockuid( const uid_t uid ) { int i,rc; /* very crude sem */ while(uidlock) usleep(10); uidlock++; for(i=0;i<=pending_uids_max;i++) { if(pending_uids[i]==uid) break; } uidlock--; if(pending_uids[i]==uid) return 1; return 0; } int nss_pool_releaselockuid( const uid_t uid ) { int i; /* very crude sem */ while(uidlock) usleep(10); uidlock++; for(i=0;i<=pending_uids_max;i++) { if(pending_uids[i]==uid) break; } if(pending_uids[i]==uid) pending_uids[i]=-1; uidlock--; return 0; } int nss_pool_isdir( char *filename ) { struct stat statbuf; int rc; if ( ! filename || ! *filename ) return 0; if ( stat(filename,&statbuf) != 0 ) return 0; if ( S_ISDIR(statbuf.st_mode) ) return 1; return 0; } int nss_pool_parsepwline( char *line, struct passwd *pwentspace ) { /* format: nscd:x:28:28:NSCD Daemon:/:/bin/false */ char *s,*t; t=s=line; while (*s && *s!=':') s++; *s=0; pwentspace->pw_name=t; t=++s; while (*s && *s!=':' && *s!='\n') s++; *s=0; pwentspace->pw_passwd=t; t=++s; while (*s && *s!=':' && *s!='\n') s++; *s=0; pwentspace->pw_uid=(uid_t)atol(t); t=++s; while (*s && *s!=':' && *s!='\n') s++; *s=0; pwentspace->pw_gid=(uid_t)atol(t); t=++s; while (*s && *s!=':' && *s!='\n') s++; *s=0; pwentspace->pw_gecos=t; t=++s; while (*s && *s!=':' && *s!='\n') s++; *s=0; pwentspace->pw_dir=t; t=++s; while (*s && *s!=':' && *s!='\n') s++; *s=0; pwentspace->pw_shell=t; return 0; } int nss_pool_sysmap_pwuid( const uid_t uid, struct passwd *syspwentspace, char *xbuffer, int xbufferlen, struct passwd **syspwent ) { char *gmd_mapfile; FILE *f; if ( ! ( (gmd_mapfile = getenv(NSSPOOL_ENV_GRIDMAPINFO)) || ( gmd_mapfile = NSSPOOL_STATIC_GMINFO) ) ) { return getpwuid_r(uid,syspwentspace,xbuffer,xbufferlen,syspwent); } else { if( xbufferlenpw_uid == uid ) { *syspwent=syspwentspace; return 0; } } fclose(f); *syspwent=NULL; return 0; } } int nss_pool_sysmap_pwnam( const char *name, struct passwd *syspwentspace, char *xbuffer, int xbufferlen, struct passwd **syspwent ) { char *gmd_mapfile; FILE *f; if ( ! ( (gmd_mapfile = getenv(NSSPOOL_ENV_GRIDMAPINFO)) || ( gmd_mapfile = NSSPOOL_STATIC_GMINFO) ) ) { return getpwnam_r(name,syspwentspace,xbuffer,xbufferlen,syspwent); } else { if( xbufferlenpw_name,name,strlen(name)) ) { *syspwent=syspwentspace; return 0; } } fclose(f); *syspwent=NULL; return 0; } } int nss_pool_findino( const ino_t ino) { int i=0; if ( pamap == NULL ) return -1; if ( pamap_size <= 0 ) return -1; for(i=0;i='a' ) *p += (tolower(*(s+1))-'a'+10) <<4; else *p += (tolower(*(s+1))-'0') <<4; if(tolower(*(s+2))>='a') *p += (tolower(*(s+2))-'a'+10); else *p += (tolower(*(s+2))-'0'); s+=2; } else { *p=*s; } } *p=0; return buf; } /* * nss_pool_initmap (void) * * Read the directory contents of the GRIDMAPDIR and fill all table * entries. Set uid and gid to -1 for later filling, and to indicate * to the getpwuid/getpwnam calls that they should pass the reuqry on * and prevent recursion * */ enum nss_status nss_pool_initmap (void) { DIR *gridmapdir; char *gmd_name; struct stat dirstat; struct dirent *gmd_entry; struct passwd *syspwent; struct passwd syspwentspace; char xbuffer[1024]; char decode_name[MAXNAMELEN]; int index; int rc; if ( ! ( (gmd_name = getenv(NSSPOOL_ENV_GRIDMAPDIR)) || ( gmd_name = NSSPOOL_STATIC_GMDIR) ) ) { return NSS_STATUS_UNAVAIL; } /* initialise the table only once */ if ( pamap ) return NSS_STATUS_SUCCESS; rc=stat(gmd_name,&dirstat); if ( rc ) return NSS_STATUS_UNAVAIL; if ( ! S_ISDIR(dirstat.st_mode) ) return NSS_STATUS_UNAVAIL; gridmapdir=opendir(gmd_name); if ( ! gridmapdir ) return NSS_STATUS_UNAVAIL; while ( gmd_entry = readdir(gridmapdir) ) { if ( *gmd_entry->d_name == '.' ) continue; index=nss_pool_findino(gmd_entry->d_ino); if(index<0) index=nss_pool_addentry(gmd_entry->d_ino); if ( *(gmd_entry->d_name) == '%' ) { *decode_name=0; nss_pool_qpdecode(gmd_entry->d_name,decode_name,sizeof(decode_name)); pamap[index].commonname=malloc(strlen(decode_name)+1); strcpy(pamap[index].commonname,decode_name); } else { pamap[index].uidname=malloc(strlen(gmd_entry->d_name)+1); strcpy(pamap[index].uidname,gmd_entry->d_name); } pamap[index].uid=NSSPOOL_UNDEF; pamap[index].gid=NSSPOOL_UNDEF; } closedir(gridmapdir); #ifdef NSSPOOL_PREINIT for(index=0;index=0) { pamap[index].uid=NSSPOOL_INIT; nss_pool_sysmap_pwnam(pamap[index].uidname,&syspwentspace,xbuffer,sizeof(xbuffer),&syspwent); pamap[index].gid=syspwent->pw_gid; pamap[index].uid=syspwent->pw_uid; } } #endif return NSS_STATUS_SUCCESS; } enum nss_status nss_pool_fill_pamap_ent( const int index, const struct passwd *syspwent ) { if(!pamap[index].uidname) pamap[index].ino=-1; if(!pamap[index].commonname) pamap[index].ino=-1; if(pamap[index].ino>=0) { pamap[index].gid=syspwent->pw_gid; pamap[index].uid=syspwent->pw_uid; pamap[index].homedir=malloc(strlen(syspwent->pw_dir)+1); strcpy(pamap[index].homedir,syspwent->pw_dir); pamap[index].shell=malloc(strlen(syspwent->pw_shell)+1); strcpy(pamap[index].shell,syspwent->pw_shell); } return NSS_STATUS_SUCCESS; } enum nss_status _nss_pool_getpwnam_r ( const char *name, struct passwd *result, char *buffer, size_t buflen ) { struct passwd *syspwent; struct passwd syspwentspace; char xbuffer[1024]; int rc; int mapidx=-1; char *gmd_name; if ( ! ( (gmd_name = getenv(NSSPOOL_ENV_GRIDMAPDIR)) || ( gmd_name = NSSPOOL_STATIC_GMDIR) ) ) { return NSS_STATUS_UNAVAIL; } if ( ! nss_pool_isdir(gmd_name) ) return NSS_STATUS_UNAVAIL; if ( ! pamap ) { rc=nss_pool_initmap(); if ( rc != NSS_STATUS_SUCCESS ) return rc; } mapidx=nss_pool_findcname(name); if ( mapidx < 0 ) return NSS_STATUS_NOTFOUND; if ( pamap[mapidx].uid < 0 ) { /* can we find a matching uid? */ nss_pool_sysmap_pwnam(pamap[mapidx].uidname,&syspwentspace,xbuffer,sizeof(xbuffer),&syspwent); if(syspwent) { nss_pool_fill_pamap_ent(mapidx,syspwent); } else return NSS_STATUS_NOTFOUND; } if(buflen<512) return NSS_STATUS_TRYAGAIN; snprintf(buffer,512,"poolaccount %s",pamap[mapidx].uidname); result->pw_gecos=buffer; result->pw_shell=pamap[mapidx].shell; result->pw_dir=pamap[mapidx].homedir; result->pw_passwd="*"; result->pw_name=pamap[mapidx].commonname; result->pw_gid=pamap[mapidx].gid; result->pw_uid=pamap[mapidx].uid; return NSS_STATUS_SUCCESS; } enum nss_status _nss_pool_getpwuid_r ( uid_t uid, struct passwd *result, char *buffer, size_t buflen ) { struct passwd *syspwent; struct passwd syspwentspace; char xbuffer[1024]; int rc; int mapidx=-1; char *gmd_name; if ( ! ( (gmd_name = getenv(NSSPOOL_ENV_GRIDMAPDIR)) || ( gmd_name = NSSPOOL_STATIC_GMDIR) ) ) { return NSS_STATUS_UNAVAIL; } if ( ! nss_pool_isdir(gmd_name) ) return NSS_STATUS_UNAVAIL; if ( ! pamap ) { rc=nss_pool_initmap(); if ( rc != NSS_STATUS_SUCCESS ) return rc; } mapidx=nss_pool_finduid(uid); if ( mapidx < 0 ) { /* maybe its our first time */ if ( nss_pool_islockuid(uid) ) { return NSS_STATUS_NOTFOUND; } else { nss_pool_addlockuid(uid); nss_pool_sysmap_pwuid(uid,&syspwentspace,xbuffer,sizeof(xbuffer),&syspwent); nss_pool_releaselockuid(uid); if(!syspwent) return NSS_STATUS_NOTFOUND; if( (mapidx=nss_pool_finduidname(syspwent->pw_name)) >=0 ) { nss_pool_fill_pamap_ent(mapidx,syspwent); /* and continue below */ } else { return NSS_STATUS_NOTFOUND; } } } if ( pamap[mapidx].uid < 0) return NSS_STATUS_NOTFOUND; if(buflen<512) return NSS_STATUS_TRYAGAIN; snprintf(buffer,512,"poolaccount %s",pamap[mapidx].uidname); result->pw_gecos=buffer; result->pw_shell=pamap[mapidx].shell; result->pw_dir=pamap[mapidx].homedir; result->pw_passwd="*"; result->pw_name=pamap[mapidx].commonname; result->pw_gid=pamap[mapidx].gid; result->pw_uid=uid; return NSS_STATUS_SUCCESS; } enum nss_status _nss_pool_setpwent (void) { struct passwd *syspwent; struct passwd syspwentspace; char xbuffer[1024]; int rc; int mapidx=-1; char *gmd_name; if ( ! ( (gmd_name = getenv(NSSPOOL_ENV_GRIDMAPDIR)) || ( gmd_name = NSSPOOL_STATIC_GMDIR) ) ) { return NSS_STATUS_UNAVAIL; } if ( ! nss_pool_isdir(gmd_name) ) return NSS_STATUS_UNAVAIL; if ( ! pamap ) { rc=nss_pool_initmap(); if ( rc != NSS_STATUS_SUCCESS ) return rc; } for(mapidx=0;mapidx= pamap_size ) return NSS_STATUS_NOTFOUND; while( pamap[getpwent_idx].uid == NSSPOOL_UNDEF && getpwent_idx < pamap_size ) getpwent_idx++; if ( getpwent_idx >= pamap_size ) return NSS_STATUS_NOTFOUND; if(buflen<512) return NSS_STATUS_TRYAGAIN; snprintf(buffer,512,"poolaccount %s",pamap[getpwent_idx].uidname); result->pw_gecos=buffer; result->pw_shell=pamap[getpwent_idx].shell; result->pw_dir=pamap[getpwent_idx].homedir; result->pw_passwd="*"; result->pw_name=pamap[getpwent_idx].commonname; result->pw_gid=pamap[getpwent_idx].gid; result->pw_uid=pamap[getpwent_idx].uid; getpwent_idx++; return NSS_STATUS_SUCCESS; }