5 * Copyright 2008, licensed under GNU Library General Public License (LGPL)
6 * see COPYING file for details
8 * derived from Frank Burkhardt's libnss_ptdb,
9 * which was derived from Todd M. Lewis' libnss_pts
13 * if you are reading this code for the first time, start at the
14 * bottom and work your way upwards
23 #include <netinet/in.h>
33 #include <sys/select.h>
34 #include <sys/socket.h>
36 #include <sys/types.h>
39 #include <afs/afsutil.h>
40 #include <afs/cellconfig.h>
41 #include <afs/com_err.h>
42 #include <afs/param.h>
43 #include <afs/ptclient.h>
44 #include <afs/pterror.h>
47 #define HOMEDIR_AUTO 0
48 #define HOMEDIR_ADMINLINK 1
49 #define HOMEDIR_PREFIX 2
51 #define SHELL_ADMINLINK 1
52 #define SHELL_USERLINK 2
54 #define AFS_MAGIC_ANONYMOUS_USERID 32766
55 #define MIN_PAG_GID 0x41000000L
56 #define MAX_PAG_GID 0x41FFFFFFL
57 #define MIN_OLDPAG_GID 0x3f00
58 #define MAX_OLDPAG_GID 0xff00
60 #define MAX_CELLNAME 256
62 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
64 extern int cpstr( char *str, char **buf, size_t *buflen);
66 extern struct ubik_client *pruclient;
68 int afs_initialized = 0;
69 char cellname[MAX_CELLNAME];
70 char homedir_prefix[300];
71 int homedir_prefix_len=0;
72 char homedirs_method=0;
75 int cpstr( char *str, char **buf, size_t *buflen) {
76 int len = strlen(str);
77 if ( len >= *buflen-1 ) return 0;
86 * Look up the name corresponding to uid, store in buffer.
88 * returns NSS_STATUS_SUCCESS, NSS_STATUS_NOTFOUND, or NSS_STATUS_UNAVAIL
90 int ptsid2name(int uid, char **buffer, int *buflen) {
97 if (uid==AFS_MAGIC_ANONYMOUS_USERID) {
98 if (!cpstr("anonymous", buffer, buflen)) return NSS_STATUS_UNAVAIL;
99 return NSS_STATUS_SUCCESS;
102 if (pthread_mutex_lock(&mutex)) return NSS_STATUS_UNAVAIL;
104 lid.idlist_val = (afs_int32*)&uid;
106 lnames.namelist_val = 0;
107 lnames.namelist_len = 0;
109 if (ubik_Call(PR_IDToName,pruclient,0,&lid,&lnames) != PRSUCCESS) {
110 pthread_mutex_unlock(&mutex);
111 return NSS_STATUS_UNAVAIL;
114 ret = NSS_STATUS_NOTFOUND;
115 for (i=0;i<lnames.namelist_len;i++) {
116 int delta = strlen(lnames.namelist_val[i]);
117 if ( (delta < buflen) && islower(*(lnames.namelist_val[i])) ) {
118 cpstr(lnames.namelist_val[i], buffer, buflen);
119 ret = NSS_STATUS_SUCCESS;
122 free(lnames.namelist_val);
123 /* free(lid.idlist_val); */
127 pthread_mutex_unlock(&mutex);
132 * Look up the uid corresponding to name, stores it in *uid.
134 * returns NSS_STATUS_SUCCESS, NSS_STATUS_NOTFOUND, or NSS_STATUS_UNAVAIL
136 int ptsname2id(char *name, uid_t* uid) {
143 if (!strcmp(name,"anonymous")) {
144 *uid = AFS_MAGIC_ANONYMOUS_USERID;
145 return NSS_STATUS_SUCCESS;
148 if (pthread_mutex_lock(&mutex)) return NSS_STATUS_UNAVAIL;
152 lnames.namelist_val = (prname*)name;
153 lnames.namelist_len = 1;
155 if (ubik_Call(PR_NameToID,pruclient,0,&lnames,&lid) != PRSUCCESS) {
156 pthread_mutex_unlock(&mutex);
157 return NSS_STATUS_UNAVAIL;
159 pthread_mutex_unlock(&mutex);
161 res = (uid_t)lid.idlist_val[0];
162 if (res == AFS_MAGIC_ANONYMOUS_USERID) return NSS_STATUS_NOTFOUND;
164 return NSS_STATUS_SUCCESS;
168 * returns zero on success
174 if (afs_initialized) return 0;
176 if (pthread_mutex_lock(&mutex)) return -1;
178 homedirs_method=HOMEDIR_PREFIX;
179 shells_method=SHELL_USERLINK;
181 len = snprintf(cellname, MAX_CELLNAME, "%s/ThisCell", AFSDIR_CLIENT_ETC_DIRPATH);
182 if (len < 0 || len >= MAX_CELLNAME) return -1;
184 thiscell=fopen(cellname,"r");
185 if (thiscell == NULL) break;
186 len=fread(cellname,1,MAX_CELLNAME,thiscell);
187 if (!feof(thiscell)) {
190 strcpy(homedir_prefix,"/tmp/\0");
191 homedir_prefix_len=5;
196 if (cellname[len-1] == '\n') len--;
198 sprintf(homedir_prefix,"/afs/%s/user/",cellname);
199 homedir_prefix_len=strlen(homedir_prefix);
201 if (pr_Initialize(0L,AFSDIR_CLIENT_ETC_DIRPATH, 0)) break;
204 pthread_mutex_unlock(&mutex);
208 pthread_mutex_unlock(&mutex);
214 result=get_homedir(char *name,char **buffer,size_t *buflen)
215 Writes the guessed Homedirectory of a given user 'name' into
216 '*buffer', increasing *buflen accordingly.
217 result == 1, only if the buffer was big enough.
219 int get_homedir(char *name, char **buffer, size_t *buflen) {
224 switch (homedirs_method) {
226 homedir_prefix[homedir_prefix_len+0]=name[0];
227 homedir_prefix[homedir_prefix_len+1]='/';
228 homedir_prefix[homedir_prefix_len+2]=name[0];
229 homedir_prefix[homedir_prefix_len+3]=name[1];
230 homedir_prefix[homedir_prefix_len+4]='/';
231 homedir_prefix[homedir_prefix_len+5]=0;
232 strncpy(&homedir_prefix[homedir_prefix_len+5],name,40);
233 if (! cpstr(homedir_prefix,buffer,buflen) ) return -1;
236 homedir_prefix[homedir_prefix_len]=0;
237 strncpy(&homedir_prefix[homedir_prefix_len],name,40);
238 if (! cpstr(homedir_prefix,buffer,buflen) ) return -1;
240 case HOMEDIR_ADMINLINK:
241 if ( snprintf(buf,256,"/afs/%s/admin/homedirs/%s",cellname,name) > 0 ) {
242 temp=readlink(buf,*buffer,*buflen);
245 *buflen = *buflen - temp - 1;
249 if (! cpstr("/tmp",buffer,buflen) ) return -1;
255 int get_shell(char *name, char **buffer, size_t *buflen) {
263 switch (shells_method) {
267 case SHELL_ADMINLINK:
268 if (snprintf(buf,256,"/afs/%s/admin/shells/%s",cellname,name)<=0) break;
269 temp = readlink(buf,*buffer,*buflen);
272 *buflen = *buflen - temp - 1;
276 if (get_homedir(name, &bufx, &bufxlen)) break;
277 if (strncpy(buf+strlen(buf),"/.loginshell",bufxlen)<=0) break;
278 temp = readlink(buf,*buffer,*buflen);
281 *buflen = *buflen - temp - 1;
284 if (! cpstr("/bin/bash",buffer,buflen) )
291 * this function is invoked by glibc to resolve the name of a numeric groupid
293 enum nss_status _nss_afs_getgrgid_r (gid_t gid, struct group *result,
294 char *buffer, size_t buflen, int *errnop) {
297 if (gid >= MIN_PAG_GID && gid <= MAX_PAG_GID) {
298 showgid = gid-MIN_PAG_GID;
299 } else if (gid >= MIN_OLDPAG_GID && gid <= MAX_OLDPAG_GID) {
300 showgid = gid-MIN_OLDPAG_GID;
303 return NSS_STATUS_NOTFOUND;
308 result->gr_name=buffer;
309 length=snprintf(buffer,buflen,"AfsPag-%x",showgid);
311 if (length < 0) break;
316 result->gr_passwd=buffer;
318 if (!cpstr("x",&buffer,&buflen)) break;
320 if (buflen < sizeof(char*)) break;
321 result->gr_mem=buffer;
322 result->gr_mem[0] = NULL;
325 return NSS_STATUS_SUCCESS;
329 return NSS_STATUS_UNAVAIL;
333 This is a the ptdb-getpwuid-function.
335 enum nss_status _nss_afs_getpwuid_r (uid_t uid, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop) {
338 if (init_afs()) return NSS_STATUS_UNAVAIL;
340 result_buf->pw_name = buffer;
341 temp = ptsid2name( uid, &buffer, &buflen);
342 if (temp != NSS_STATUS_SUCCESS) {
347 #ifdef LIMIT_USERNAME_CHARS
348 if ( strlen(result_buf->pw_name) > LIMIT_USERNAME_CHARS ) {
349 result_buf->pw_name[LIMIT_USERNAME_CHARS] = '\0';
350 buflen = buflen + ( buffer - &result_buf->pw_name[LIMIT_USERNAME_CHARS+1] );
351 buffer = &result_buf->pw_name[LIMIT_USERNAME_CHARS+1];
356 /* set the password to "x" */
357 result_buf->pw_passwd = buffer;
358 if ( ! cpstr("x",&buffer, &buflen) ) break;
359 /* the uid and gid are both the uid passed in */
360 result_buf->pw_uid = uid;
361 result_buf->pw_gid = 65534;
362 /* make the gecos the same as the PTS name */
363 result_buf->pw_gecos = buffer;
364 if ( ! cpstr(result_buf->pw_name, &buffer, &buflen ) ) break;
366 // Set the homedirectory
367 result_buf->pw_dir = buffer;
368 if ( get_homedir(result_buf->pw_name,&buffer,&buflen) ) break;
370 // Set the login shell
371 result_buf->pw_shell = buffer;
372 if ( get_shell(result_buf->pw_name,&buffer,&buflen) ) break;
375 return NSS_STATUS_SUCCESS;
379 return NSS_STATUS_UNAVAIL;
384 * This is the ptdb-getpwnam-function.
386 enum nss_status _nss_afs_getpwnam_r (char *name, struct passwd *result_buf, char *buffer, size_t buflen, int *errnop) {
390 if (init_afs()) return NSS_STATUS_UNAVAIL;
392 temp = ptsname2id(name,&uid);
393 if (temp != NSS_STATUS_SUCCESS) {
398 // This causes an additional PTDB-lookup and should be removed in the future
399 return _nss_afs_getpwuid_r (uid, result_buf,buffer,buflen, errnop);