/** * @brief Get numeric credentials from request * * @todo This MUST be refactored to not use TI-RPC private structures. * Instead, export appropriate functions from lib(n)tirpc. * * fills out creds in op_ctx * * @param[in] req Incoming request. * * @return NFS4_OK if successful, NFS4ERR_ACCESS otherwise. * */ nfsstat4 nfs_req_creds(struct svc_req *req) { unsigned int i; const char *auth_label = "UNKNOWN"; gid_t **garray_copy = &op_ctx->caller_garray_copy; #ifdef _HAVE_GSSAPI struct svc_rpc_gss_data *gd = NULL; char principal[MAXNAMLEN + 1]; #endif /* Make sure we clear out all the cred_flags except CREDS_LOADED and * CREDS_ANON. */ op_ctx->cred_flags &= CREDS_LOADED | CREDS_ANON; switch (req->rq_cred.oa_flavor) { case AUTH_NONE: /* Nothing to be done here... */ op_ctx->cred_flags |= CREDS_LOADED | CREDS_ANON; auth_label = "AUTH_NONE"; break; case AUTH_SYS: if ((op_ctx->cred_flags & CREDS_LOADED) == 0) { struct authunix_parms *creds = NULL; /* We map the rq_cred to Authunix_parms */ creds = (struct authunix_parms *) req->rq_clntcred; op_ctx->original_creds.caller_uid = creds->aup_uid; op_ctx->original_creds.caller_gid = creds->aup_gid; op_ctx->original_creds.caller_glen = creds->aup_len; op_ctx->original_creds.caller_garray = creds->aup_gids; op_ctx->cred_flags |= CREDS_LOADED; } /* Copy original_creds creds */ *op_ctx->creds = op_ctx->original_creds; /* Do we trust AUTH_SYS creds for groups or not ? */ if ((op_ctx->export_perms->options & EXPORT_OPTION_MANAGE_GIDS) != 0) { op_ctx->cred_flags |= MANAGED_GIDS; garray_copy = &op_ctx->managed_garray_copy; } auth_label = "AUTH_SYS"; break; #ifdef _HAVE_GSSAPI case RPCSEC_GSS: if ((op_ctx->cred_flags & CREDS_LOADED) == 0) { /* Get the gss data to process them */ gd = SVCAUTH_PRIVATE(req->rq_auth); memcpy(principal, gd->cname.value, gd->cname.length); principal[gd->cname.length] = 0; LogMidDebug(COMPONENT_DISPATCH, "Mapping RPCSEC_GSS principal %s to uid/gid", principal); /* Convert to uid */ #if _MSPAC_SUPPORT if (!principal2uid(principal, &op_ctx->original_creds.caller_uid, &op_ctx->original_creds.caller_gid, gd)) { #else if (!principal2uid(principal, &op_ctx->original_creds.caller_uid, &op_ctx->original_creds.caller_gid) ) { #endif LogWarn(COMPONENT_IDMAPPER, "Could not map principal %s to uid", principal); /* For compatibility with Linux knfsd, we set * the uid/gid to anonymous when a name->uid * mapping can't be found. */ op_ctx->cred_flags |= CREDS_ANON | CREDS_LOADED; auth_label = "RPCSEC_GSS (no mapping)"; break; } op_ctx->cred_flags |= CREDS_LOADED; } auth_label = "RPCSEC_GSS"; op_ctx->cred_flags |= MANAGED_GIDS; garray_copy = &op_ctx->managed_garray_copy; break; #endif /* _USE_GSSRPC */ default: LogMidDebug(COMPONENT_DISPATCH, "FAILURE: Request xid=%u, has unsupported authentication %d", req->rq_xid, req->rq_cred.oa_flavor); /* Reject the request for weak authentication and * return to worker */ return NFS4ERR_ACCESS; break; } /****************************************************************/ /* Now check for anon creds or id squashing */ /****************************************************************/ if ((op_ctx->cred_flags & CREDS_ANON) != 0 || ((op_ctx->export_perms->options & EXPORT_OPTION_ALL_ANONYMOUS) != 0) || ((op_ctx->export_perms->options & EXPORT_OPTION_ROOT) == 0 && op_ctx->original_creds.caller_uid == 0)) { op_ctx->creds->caller_uid = op_ctx->export_perms->anonymous_uid; op_ctx->creds->caller_gid = op_ctx->export_perms->anonymous_gid; op_ctx->creds->caller_glen = 0; LogMidDebugAlt(COMPONENT_DISPATCH, COMPONENT_EXPORT, "%s creds squashed to uid=%u, gid=%u", auth_label, op_ctx->creds->caller_uid, op_ctx->creds->caller_gid); op_ctx->cred_flags |= UID_SQUASHED | GID_SQUASHED; return NFS4_OK; } /* Now we will use the original_creds uid from original credential */ op_ctx->creds->caller_uid = op_ctx->original_creds.caller_uid; /****************************************************************/ /* Now sqush group or use original_creds gid */ /****************************************************************/ if ((op_ctx->export_perms->options & EXPORT_OPTION_ROOT) == 0 && op_ctx->original_creds.caller_gid == 0) { /* Squash gid */ op_ctx->creds->caller_gid = op_ctx->export_perms->anonymous_gid; op_ctx->cred_flags |= GID_SQUASHED; } else { /* Use original_creds gid */ op_ctx->creds->caller_gid = op_ctx->original_creds.caller_gid; } /****************************************************************/ /* Check if we have manage_gids. */ /****************************************************************/ if ((op_ctx->cred_flags & MANAGED_GIDS) != 0) { /* Fetch the group data if required */ if (op_ctx->caller_gdata == NULL && !uid2grp(op_ctx->original_creds.caller_uid, &op_ctx->caller_gdata)) { /** @todo: do we really want to bail here? */ LogCrit(COMPONENT_DISPATCH, "Attempt to fetch managed_gids failed"); return NFS4ERR_ACCESS; } op_ctx->creds->caller_glen = op_ctx->caller_gdata->nbgroups; op_ctx->creds->caller_garray = op_ctx->caller_gdata->groups; } else { /* Use the original_creds group list */ op_ctx->creds->caller_glen = op_ctx->original_creds.caller_glen; op_ctx->creds->caller_garray = op_ctx->original_creds.caller_garray; } /****************************************************************/ /* Check the garray for gid 0 to squash */ /****************************************************************/ /* If no root squashing in caller_garray, return now */ if ((op_ctx->export_perms->options & EXPORT_OPTION_ROOT) != 0 || op_ctx->creds->caller_glen == 0) goto out; for (i = 0; i < op_ctx->creds->caller_glen; i++) { if (op_ctx->creds->caller_garray[i] == 0) { /* Meed to make a copy, or use the old copy */ if ((*garray_copy) == NULL) { /* Make a copy of the active garray */ (*garray_copy) = gsh_malloc(op_ctx->creds->caller_glen * sizeof(gid_t)); memcpy((*garray_copy), op_ctx->creds->caller_garray, op_ctx->creds->caller_glen * sizeof(gid_t)); } /* Now squash the root id. Since the original copy is * always the same, any root ids in it were still in * the same place, so even if using a copy that had a * different anonymous_gid, we're fine. */ (*garray_copy)[i] = op_ctx->export_perms->anonymous_gid; /* Indicate we squashed the caller_garray */ op_ctx->cred_flags |= GARRAY_SQUASHED; } } /* If we squashed the caller_garray, use the squashed copy */ if ((op_ctx->cred_flags & GARRAY_SQUASHED) != 0) op_ctx->creds->caller_garray = *garray_copy; out: LogMidDebugAlt(COMPONENT_DISPATCH, COMPONENT_EXPORT, "%s creds mapped to uid=%u, gid=%u%s, glen=%d%s", auth_label, op_ctx->creds->caller_uid, op_ctx->creds->caller_gid, (op_ctx->cred_flags & GID_SQUASHED) != 0 ? " (squashed)" : "", op_ctx->creds->caller_glen, (op_ctx->cred_flags & MANAGED_GIDS) != 0 ? ((op_ctx->cred_flags & GARRAY_SQUASHED) != 0 ? " (managed and squashed)" : " (managed)") : ((op_ctx->cred_flags & GARRAY_SQUASHED) != 0 ? " (squashed)" : "")); return NFS4_OK; } /** * @brief Initialize request context and credentials. * */ void init_credentials(void) { memset(op_ctx->creds, 0, sizeof(*op_ctx->creds)); memset(&op_ctx->original_creds, 0, sizeof(op_ctx->original_creds)); op_ctx->creds->caller_uid = op_ctx->export_perms->anonymous_uid; op_ctx->creds->caller_gid = op_ctx->export_perms->anonymous_gid; op_ctx->caller_gdata = NULL; op_ctx->caller_garray_copy = NULL; op_ctx->managed_garray_copy = NULL; op_ctx->cred_flags = 0; }
/** * * get_req_uid_gid: * * * * @param ptr_req [IN] incoming request. * @param pexport_client [IN] related export client * @param pexport [IN] related export entry * @param user_credentials [OUT] Filled in structure with uid and gids * * @return TRUE if successful, FALSE otherwise * */ int get_req_uid_gid(struct svc_req *ptr_req, exportlist_client_entry_t * pexport_client, exportlist_t * pexport, struct user_cred *user_credentials) { struct authunix_parms *punix_creds = NULL; unsigned int rpcxid = 0; #ifdef _HAVE_GSSAPI struct svc_rpc_gss_data *gd = NULL; char principal[MAXNAMLEN]; #endif if (user_credentials == NULL) return FALSE; rpcxid = get_rpc_xid(ptr_req); switch (ptr_req->rq_cred.oa_flavor) { case AUTH_NONE: /* Nothing to be done here... */ LogFullDebug(COMPONENT_DISPATCH, "Request xid=%u has authentication AUTH_NONE", rpcxid); break; case AUTH_UNIX: LogFullDebug(COMPONENT_DISPATCH, "Request xid=%u has authentication AUTH_UNIX", rpcxid); /* We map the rq_cred to Authunix_parms */ punix_creds = (struct authunix_parms *)ptr_req->rq_clntcred; /* Get the uid/gid couple */ user_credentials->caller_uid = punix_creds->aup_uid; user_credentials->caller_gid = punix_creds->aup_gid; user_credentials->caller_glen = punix_creds->aup_len; user_credentials->caller_garray = punix_creds->aup_gids; LogFullDebug(COMPONENT_DISPATCH, "----> Uid=%u Gid=%u", (unsigned int)user_credentials->caller_uid, (unsigned int)user_credentials->caller_gid); break; #ifdef _HAVE_GSSAPI case RPCSEC_GSS: LogFullDebug(COMPONENT_DISPATCH, "Request xid=%u has authentication RPCSEC_GSS", rpcxid); /* Get the gss data to process them */ gd = SVCAUTH_PRIVATE(ptr_req->rq_xprt->xp_auth); if(isFullDebug(COMPONENT_RPCSEC_GSS)) { OM_uint32 maj_stat = 0; OM_uint32 min_stat = 0; char ptr[256]; gss_buffer_desc oidbuff; LogFullDebug(COMPONENT_RPCSEC_GSS, "----> RPCSEC_GSS svc=%u RPCSEC_GSS_SVC_NONE=%u RPCSEC_GSS_SVC_INTEGRITY=%u RPCSEC_GSS_SVC_PRIVACY=%u", gd->sec.svc, RPCSEC_GSS_SVC_NONE, RPCSEC_GSS_SVC_INTEGRITY, RPCSEC_GSS_SVC_PRIVACY); memcpy(&ptr, (void *)gd->ctx + 4, 4); LogFullDebug(COMPONENT_RPCSEC_GSS, "----> Client=%s length=%lu Qop=%u established=%u gss_ctx_id=%p|%p", (char *)gd->cname.value, gd->cname.length, gd->established, gd->sec.qop, gd->ctx, ptr); if((maj_stat = gss_oid_to_str(&min_stat, gd->sec.mech, &oidbuff)) != GSS_S_COMPLETE) { LogFullDebug(COMPONENT_DISPATCH, "Error in gss_oid_to_str: %u|%u", maj_stat, min_stat); } else { LogFullDebug(COMPONENT_RPCSEC_GSS, "----> Client mech=%s len=%lu", (char *)oidbuff.value, oidbuff.length); // Release the string (void)gss_release_buffer(&min_stat, &oidbuff); } } LogFullDebug(COMPONENT_RPCSEC_GSS, "Mapping principal %s to uid/gid", (char *)gd->cname.value); memcpy(principal, gd->cname.value, gd->cname.length); principal[gd->cname.length] = 0; /* Convert to uid */ if(!principal2uid(principal, &user_credentials->caller_uid)) { LogWarn(COMPONENT_IDMAPPER, "WARNING: Could not map principal to uid; mapping principal " "to anonymous uid/gid"); /* For compatibility with Linux knfsd, we set the uid/gid * to anonymous when a name->uid mapping can't be found. */ user_credentials->caller_uid = pexport->anonymous_uid; user_credentials->caller_gid = pexport->anonymous_gid; /* No alternate groups for "nobody" */ user_credentials->caller_glen = 0 ; user_credentials->caller_garray = NULL ; return TRUE; } if(uidgidmap_get(user_credentials->caller_uid, &user_credentials->caller_gid) != ID_MAPPER_SUCCESS) { LogMajor(COMPONENT_DISPATCH, "FAILURE: Could not resolve uidgid map for %u", user_credentials->caller_uid); user_credentials->caller_gid = -1; } LogFullDebug(COMPONENT_DISPATCH, "----> Uid=%u Gid=%u", (unsigned int)user_credentials->caller_uid, (unsigned int)user_credentials->caller_gid); user_credentials->caller_glen = 0; user_credentials->caller_garray = 0; break; #endif /* _USE_GSSRPC */ default: LogFullDebug(COMPONENT_DISPATCH, "FAILURE: Request xid=%u, has unsupported authentication %d", rpcxid, ptr_req->rq_cred.oa_flavor); /* Reject the request for weak authentication and return to worker */ return FALSE; break; } /* switch( ptr_req->rq_cred.oa_flavor ) */ return TRUE; }