return NSS_STATUS_UNAVAIL if used without nscd
[hcoop/debian/libnss-afs.git] / nss_afs.c
index 3ef57b9..de52438 100644 (file)
--- a/nss_afs.c
+++ b/nss_afs.c
@@ -52,6 +52,7 @@
 #include <string.h>
 #include <sys/select.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -78,6 +79,7 @@
 #define MAX_OLDPAG_GID             0xff00
 
 #define MAXCELLNAMELEN             256
+#define MAXUSERNAMELEN             256
 
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -86,6 +88,7 @@ extern struct ubik_client *pruclient;
 int  afs_initialized = 0;
 char cellname[MAXCELLNAMELEN];
 char homedir_prefix[MAXPATHLEN];
+char cell_root[MAXPATHLEN];
 int  homedir_prefix_len=0;
 char homedirs_method=0;
 char shells_method=0;
@@ -113,7 +116,7 @@ enum nss_status ptsid2name(int uid, char **buffer, int *buflen) {
   idlist lid;
   namelist lnames;
 
-  init_afs();
+  if (init_afs()) return NSS_STATUS_UNAVAIL;
 
   if (uid==AFS_MAGIC_ANONYMOUS_USERID) {
     if (!cpstr("anonymous", buffer, buflen)) return NSS_STATUS_UNAVAIL;
@@ -128,6 +131,7 @@ enum nss_status ptsid2name(int uid, char **buffer, int *buflen) {
   lnames.namelist_len = 0;
 
   if (ubik_Call(PR_IDToName,pruclient,0,&lid,&lnames) != PRSUCCESS) {
+    perror("ubik_Call() in ptsid2name() failed\n");
     pthread_mutex_unlock(&mutex);
     return NSS_STATUS_UNAVAIL;
   }
@@ -156,8 +160,9 @@ enum nss_status ptsname2id(char *name, uid_t* uid) {
   int res;
   idlist lid;
   namelist lnames;
+  char uname[MAXUSERNAMELEN];
 
-  init_afs();
+  if (init_afs()) return NSS_STATUS_UNAVAIL;
   
   if (!strcmp(name,"anonymous")) {
     *uid = AFS_MAGIC_ANONYMOUS_USERID;
@@ -168,10 +173,13 @@ enum nss_status ptsname2id(char *name, uid_t* uid) {
 
   lid.idlist_val = 0;
   lid.idlist_len = 0;
-  lnames.namelist_val = (prname*)name;
+  lnames.namelist_val = (prname*)uname;
+  // apparently ubik expects to be able to modify this?
+  strncpy(uname, name, MAXUSERNAMELEN);
   lnames.namelist_len = 1;
 
   if (ubik_Call(PR_NameToID,pruclient,0,&lnames,&lid) != PRSUCCESS) {
+    perror("ubik_Call() in ptsname2id() failed\n");
     pthread_mutex_unlock(&mutex);
     return NSS_STATUS_UNAVAIL;
   }
@@ -189,9 +197,38 @@ enum nss_status ptsname2id(char *name, uid_t* uid) {
 int init_afs() {
   FILE *thiscell;
   int len;
+  struct stat statbuf;
+
+  char buf[6];
+  int fd;
+  int pos;
 
-  if (afs_initialized) return 0;
+  if (afs_initialized) {
+    /* wait until /afs/@cell/ appears as a proxy for "the network is up" */
+    if (stat(cell_root, &statbuf)) return -1;
+    return 0;
+  }
 
+  // check to make sure that we are running inside nscd
+  pos = 0;
+  fd = open("/proc/self/cmdline", O_RDONLY);
+  if (fd==-1) return -1;
+  while(1) {
+    int numread;
+    numread = read(fd, buf+pos, 1);
+    if (buf[ (pos+5)%6 ] == 'd' &&
+        buf[ (pos+4)%6 ] == 'c' &&
+        buf[ (pos+3)%6 ] == 's' &&
+        buf[ (pos+2)%6 ] == 'n' &&
+        (buf[(pos+1)%6 ] == '/' || pos==4) &&
+        (buf[(pos+0)%6 ] ==  0  || numread==-1)
+        )
+      break;
+    pos = (pos+1)%6;
+    if (numread==0) { close(fd); return -1; }
+  }
+  close(fd);
+  
   if (pthread_mutex_lock(&mutex)) return -1;
   do {
     homedirs_method=HOMEDIR_PREFIX;
@@ -215,10 +252,21 @@ int init_afs() {
 
     if (cellname[len-1] == '\n') len--;
     cellname[len]='\0';
+
+    /* wait until /afs/@cell/ appears as a proxy for "the network is up" */
+    sprintf(cell_root,"/afs/%s/",cellname);
+    if (stat(cell_root, &statbuf)) break;
+
     sprintf(homedir_prefix,"/afs/%s/user/",cellname);
     homedir_prefix_len=strlen(homedir_prefix);
-    
-    if (pr_Initialize(0L,AFSDIR_CLIENT_ETC_DIRPATH, 0)) break;
+
+    /* time out requests after 5 seconds to avoid hanging things */
+    rx_SetRxDeadTime(5);    
+
+    if (pr_Initialize(0L,AFSDIR_CLIENT_ETC_DIRPATH, 0)) {
+      perror("pr_Initialize() failed\n");
+      break;
+    }
     
     afs_initialized = 1;
     pthread_mutex_unlock(&mutex);
@@ -386,6 +434,14 @@ enum nss_status fill_result_buf(uid_t uid,
     result_buf->pw_shell = buffer;
     if ( get_shell(result_buf->pw_name,&buffer,&buflen) ) break;
 
+#ifdef LIMIT_USERNAME_CHARS
+    if ( strlen(result_buf->pw_name) > LIMIT_USERNAME_CHARS ) {
+      result_buf->pw_name[LIMIT_USERNAME_CHARS] = '\0';
+      buflen = buflen + ( buffer - &result_buf->pw_name[LIMIT_USERNAME_CHARS+1] );
+      buffer = &result_buf->pw_name[LIMIT_USERNAME_CHARS+1];
+    }
+#endif
+
     *errnop = errno;
     return NSS_STATUS_SUCCESS;
   } while(0);
@@ -417,14 +473,6 @@ enum nss_status _nss_afs_getpwuid_r (uid_t uid,
     return temp;
   }
 
-#ifdef LIMIT_USERNAME_CHARS
-  if ( strlen(result_buf->pw_name) > LIMIT_USERNAME_CHARS ) {
-    result_buf->pw_name[LIMIT_USERNAME_CHARS] = '\0';
-    buflen = buflen + ( buffer - &result_buf->pw_name[LIMIT_USERNAME_CHARS+1] );
-    buffer = &result_buf->pw_name[LIMIT_USERNAME_CHARS+1];
-  }
-#endif
-
   return fill_result_buf(uid, name, result_buf, buffer, buflen, errnop);
 }