+/*
+ * When creating file system objects:
+ * Don't bother setting UID if it's the same as the credential performing the create.
+ * Don't bother setting GID if it's the same as the directory or credential.
+ */
+void
+nfs_avoid_needless_id_setting_on_create(nfsnode_t dnp, struct vnode_attr *vap, vfs_context_t ctx)
+{
+ if (VATTR_IS_ACTIVE(vap, va_uid)) {
+ if (kauth_cred_getuid(vfs_context_ucred(ctx)) == vap->va_uid) {
+ VATTR_CLEAR_ACTIVE(vap, va_uid);
+ VATTR_CLEAR_ACTIVE(vap, va_uuuid);
+ }
+ }
+ if (VATTR_IS_ACTIVE(vap, va_gid)) {
+ if ((vap->va_gid == dnp->n_vattr.nva_gid) ||
+ (kauth_cred_getgid(vfs_context_ucred(ctx)) == vap->va_gid)) {
+ VATTR_CLEAR_ACTIVE(vap, va_gid);
+ VATTR_CLEAR_ACTIVE(vap, va_guuid);
+ }
+ }
+}
+
+/*
+ * Convert a universal address string to a sockaddr structure.
+ *
+ * Universal addresses can be in the following formats:
+ *
+ * d = decimal (IPv4)
+ * x = hexadecimal (IPv6)
+ * p = port (decimal)
+ *
+ * d.d.d.d
+ * d.d.d.d.p.p
+ * x:x:x:x:x:x:x:x
+ * x:x:x:x:x:x:x:x.p.p
+ * x:x:x:x:x:x:d.d.d.d
+ * x:x:x:x:x:x:d.d.d.d.p.p
+ *
+ * IPv6 strings can also have a series of zeroes elided
+ * IPv6 strings can also have a %scope suffix at the end (after any port)
+ *
+ * rules & exceptions:
+ * - value before : is hex
+ * - value before . is dec
+ * - once . hit, all values are dec
+ * - hex+port case means value before first dot is actually hex
+ * - . is always preceded by digits except if last hex was double-colon
+ *
+ * scan, converting #s to bytes
+ * first time a . is encountered, scan the rest to count them.
+ * 2 dots = just port
+ * 3 dots = just IPv4 no port
+ * 5 dots = IPv4 and port
+ */
+
+#define IS_DIGIT(C) \
+ (((C) >= '0') && ((C) <= '9'))
+
+#define IS_XDIGIT(C) \
+ (IS_DIGIT(C) || \
+ (((C) >= 'A') && ((C) <= 'F')) || \
+ (((C) >= 'a') && ((C) <= 'f')))
+
+int
+nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr)
+{
+ const char *p, *pd; /* pointers to current character in scan */
+ const char *pnum; /* pointer to current number to decode */
+ const char *pscope; /* pointer to IPv6 scope ID */
+ uint8_t a[18]; /* octet array to store address bytes */
+ int i; /* index of next octet to decode */
+ int dci; /* index of octet to insert double-colon zeroes */
+ int dcount, xdcount; /* count of digits in current number */
+ int needmore; /* set when we know we need more input (e.g. after colon, period) */
+ int dots; /* # of dots */
+ int hex; /* contains hex values */
+ unsigned long val; /* decoded value */
+ int s; /* index used for sliding array to insert elided zeroes */
+
+#define HEXVALUE 0
+#define DECIMALVALUE 1
+#define GET(TYPE) \
+ do { \
+ if ((dcount <= 0) || (dcount > (((TYPE) == DECIMALVALUE) ? 3 : 4))) \
+ return (0); \
+ if (((TYPE) == DECIMALVALUE) && xdcount) \
+ return (0); \
+ val = strtoul(pnum, NULL, ((TYPE) == DECIMALVALUE) ? 10 : 16); \
+ if (((TYPE) == DECIMALVALUE) && (val >= 256)) \
+ return (0); \
+ /* check if there is room left in the array */ \
+ if (i > (int)(sizeof(a) - (((TYPE) == HEXVALUE) ? 2 : 1) - ((dci != -1) ? 2 : 0))) \
+ return (0); \
+ if ((TYPE) == HEXVALUE) \
+ a[i++] = ((val >> 8) & 0xff); \
+ a[i++] = (val & 0xff); \
+ } while (0)
+
+ hex = 0;
+ dots = 0;
+ dci = -1;
+ i = dcount = xdcount = 0;
+ pnum = p = uaddr;
+ pscope = NULL;
+ needmore = 1;
+ if ((*p == ':') && (*++p != ':')) /* if it starts with colon, gotta be a double */
+ return (0);
+
+ while (*p) {
+ if (IS_XDIGIT(*p)) {
+ dcount++;
+ if (!IS_DIGIT(*p))
+ xdcount++;
+ needmore = 0;
+ p++;
+ } else if (*p == '.') {
+ /* rest is decimal IPv4 dotted quad and/or port */
+ if (!dots) {
+ /* this is the first, so count them */
+ for (pd = p; *pd; pd++) {
+ if (*pd == '.') {
+ if (++dots > 5)
+ return (0);
+ } else if (hex && (*pd == '%')) {
+ break;
+ } else if ((*pd < '0') || (*pd > '9')) {
+ return (0);
+ }
+ }
+ if ((dots != 2) && (dots != 3) && (dots != 5))
+ return (0);
+ if (hex && (dots == 2)) { /* hex+port */
+ if (!dcount && needmore)
+ return (0);
+ if (dcount) /* last hex may be elided zero */
+ GET(HEXVALUE);
+ } else {
+ GET(DECIMALVALUE);
+ }
+ } else {
+ GET(DECIMALVALUE);
+ }
+ dcount = xdcount = 0;
+ needmore = 1;
+ pnum = ++p;
+ } else if (*p == ':') {
+ hex = 1;
+ if (dots)
+ return (0);
+ if (!dcount) { /* missing number, probably double colon */
+ if (dci >= 0) /* can only have one double colon */
+ return (0);
+ dci = i;
+ needmore = 0;
+ } else {
+ GET(HEXVALUE);
+ dcount = xdcount = 0;
+ needmore = 1;
+ }
+ pnum = ++p;
+ } else if (*p == '%') { /* scope ID delimiter */
+ if (!hex)
+ return (0);
+ p++;
+ pscope = p;
+ break;
+ } else { /* unexpected character */
+ return (0);
+ }
+ }
+ if (needmore && !dcount)
+ return (0);
+ if (dcount) /* decode trailing number */
+ GET(dots ? DECIMALVALUE : HEXVALUE);
+ if (dci >= 0) { /* got a double-colon at i, need to insert a range of zeroes */
+ /* if we got a port, slide to end of array */
+ /* otherwise, slide to end of address (non-port) values */
+ int end = ((dots == 2) || (dots == 5)) ? sizeof(a) : (sizeof(a) - 2);
+ if (i % 2) /* length of zero range must be multiple of 2 */
+ return (0);
+ if (i >= end) /* no room? */
+ return (0);
+ /* slide (i-dci) numbers up from index dci */
+ for (s=0; s < (i - dci); s++)
+ a[end-1-s] = a[i-1-s];
+ /* zero (end-i) numbers at index dci */
+ for (s=0; s < (end - i); s++)
+ a[dci+s] = 0;
+ i = end;
+ }
+
+ /* copy out resulting socket address */
+ if (hex) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
+ if ((((dots == 0) || (dots == 3)) && (i != (sizeof(a)-2))))
+ return (0);
+ if ((((dots == 2) || (dots == 5)) && (i != sizeof(a))))
+ return (0);
+ bzero(sin6, sizeof(struct sockaddr_in6));
+ sin6->sin6_len = sizeof(struct sockaddr_in6);
+ sin6->sin6_family = AF_INET6;
+ bcopy(a, &sin6->sin6_addr.s6_addr, sizeof(struct in6_addr));
+ if ((dots == 5) || (dots == 2))
+ sin6->sin6_port = htons((a[16] << 8) | a[17]);
+ if (pscope) {
+ for (p=pscope; IS_DIGIT(*p); p++)
+ ;
+ if (*p && !IS_DIGIT(*p)) { /* name */
+ ifnet_t interface = NULL;
+ if (ifnet_find_by_name(pscope, &interface) == 0)
+ sin6->sin6_scope_id = ifnet_index(interface);
+ if (interface)
+ ifnet_release(interface);
+ } else { /* decimal number */
+ sin6->sin6_scope_id = strtoul(pscope, NULL, 10);
+ }
+ /* XXX should we also embed scope id for linklocal? */
+ }
+ } else {
+ struct sockaddr_in *sin = (struct sockaddr_in*)addr;
+ if ((dots != 3) && (dots != 5))
+ return (0);
+ if ((dots == 3) && (i != 4))
+ return (0);
+ if ((dots == 5) && (i != 6))
+ return (0);
+ bzero(sin, sizeof(struct sockaddr_in));
+ sin->sin_len = sizeof(struct sockaddr_in);
+ sin->sin_family = AF_INET;
+ bcopy(a, &sin->sin_addr.s_addr, sizeof(struct in_addr));
+ if (dots == 5)
+ sin->sin_port = htons((a[4] << 8) | a[5]);
+ }
+ return (1);
+}
+
+
+/* NFS Client debugging support */
+uint32_t nfs_debug_ctl;
+
+#include <libkern/libkern.h>
+#include <stdarg.h>
+
+void
+nfs_printf(int facility, int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ if ((uint32_t)level > NFS_DEBUG_LEVEL)
+ return;
+ if (NFS_DEBUG_FACILITY && !((uint32_t)facility & NFS_DEBUG_FACILITY))
+ return;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+