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
);