+
+/*!
+ * Store n random bytes an buf
+ */
+void randombytes(void *buf, int n)
+{
+ char *p = (char *)buf;
+ int fd, i;
+ struct timeval tv;
+
+ if ((fd = open("/dev/urandom", O_RDONLY)) != -1) {
+ /* generate from /dev/urandom */
+ if (read(fd, buf, n) != n) {
+ close(fd);
+ fd = -1;
+ } else {
+ close(fd);
+ /* fd now != -1, so srandom wont be called below */
+ }
+ }
+
+ if (fd == -1) {
+ gettimeofday(&tv, NULL);
+ srandom((unsigned int)tv.tv_usec);
+ for (i=0 ; i < n ; i++)
+ p[i] = random() & 0xFF;
+ }
+
+ return;
+}
+
+int gmem(gid_t gid, int ngroups, gid_t *groups)
+{
+ int i;
+
+ for ( i = 0; i < ngroups; i++ ) {
+ if ( groups[ i ] == gid ) {
+ return( 1 );
+ }
+ }
+ return( 0 );
+}
+
+/*
+ * realpath() replacement that always allocates storage for returned path
+ */
+char *realpath_safe(const char *path)
+{
+ char *resolved_path;
+
+#ifdef REALPATH_TAKES_NULL
+ if ((resolved_path = realpath(path, NULL)) == NULL) {
+ LOG(log_debug, logtype_afpd, "realpath() cannot resolve path \"%s\"", path);
+ return NULL;
+ }
+ return resolved_path;
+#else
+ if ((resolved_path = malloc(MAXPATHLEN+1)) == NULL)
+ return NULL;
+ if (realpath(path, resolved_path) == NULL) {
+ free(resolved_path);
+ LOG(log_debug, logtype_afpd, "realpath() cannot resolve path \"%s\"", path);
+ return NULL;
+ }
+ /* Safe some memory */
+ char *tmp;
+ if ((tmp = strdup(resolved_path)) == NULL) {
+ free(resolved_path);
+ return NULL;
+ }
+ free(resolved_path);
+ resolved_path = tmp;
+ return resolved_path;
+#endif
+}
+
+/**
+ * Returns pointer to static buffer with basename of path
+ **/
+const char *basename_safe(const char *path)
+{
+ static char buf[MAXPATHLEN+1];
+ strlcpy(buf, path, MAXPATHLEN);
+ return basename(buf);
+}
+
+/**
+ * extended strtok allows the quoted strings
+ * modified strtok.c in glibc 2.0.6
+ **/
+char *strtok_quote(char *s, const char *delim)
+{
+ static char *olds = NULL;
+ char *token;
+
+ if (s == NULL)
+ s = olds;
+
+ /* Scan leading delimiters. */
+ s += strspn (s, delim);
+ if (*s == '\0')
+ return NULL;
+
+ /* Find the end of the token. */
+ token = s;
+
+ if (token[0] == '\"') {
+ token++;
+ s = strpbrk (token, "\"");
+ } else {
+ s = strpbrk (token, delim);
+ }
+
+ if (s == NULL) {
+ /* This token finishes the string. */
+ olds = strchr (token, '\0');
+ } else {
+ /* Terminate the token and make OLDS point past it. */
+ *s = '\0';
+ olds = s + 1;
+ }
+ return token;
+}
+
+int set_groups(AFPObj *obj, struct passwd *pwd)
+{
+ if (initgroups(pwd->pw_name, pwd->pw_gid) < 0)
+ LOG(log_error, logtype_afpd, "initgroups(%s, %d): %s", pwd->pw_name, pwd->pw_gid, strerror(errno));
+
+ if ((obj->ngroups = getgroups(0, NULL)) < 0) {
+ LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno));
+ return -1;
+ }
+
+ if (obj->groups)
+ free(obj->groups);
+ if (NULL == (obj->groups = calloc(obj->ngroups, sizeof(gid_t))) ) {
+ LOG(log_error, logtype_afpd, "login: %s calloc: %d", obj->ngroups);
+ return -1;
+ }
+
+ if ((obj->ngroups = getgroups(obj->ngroups, obj->groups)) < 0 ) {
+ LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+#define GROUPSTR_BUFSIZE 1024
+const char *print_groups(int ngroups, gid_t *groups)
+{
+ static char groupsstr[GROUPSTR_BUFSIZE];
+ int i;
+ char *s = groupsstr;
+
+ if (ngroups == 0)
+ return "-";
+
+ for (i = 0; (i < ngroups) && (s < &groupsstr[GROUPSTR_BUFSIZE]); i++) {
+ s += snprintf(s, &groupsstr[GROUPSTR_BUFSIZE] - s, " %u", groups[i]);
+ }
+
+ return groupsstr;
+}