+/*
+ * If a digest prefix is present, fills in struct sudo_digest
+ * and returns a pointer to it, updating cmnd to point to the
+ * command after the digest.
+ */
+static struct sudo_digest *
+sudo_sss_extract_digest(char **cmnd, struct sudo_digest *digest)
+{
+ char *ep, *cp = *cmnd;
+ int digest_type = SUDO_DIGEST_INVALID;
+ debug_decl(sudo_sss_check_command, SUDO_DEBUG_LDAP)
+
+ /*
+ * Check for and extract a digest prefix, e.g.
+ * sha224:d06a2617c98d377c250edd470fd5e576327748d82915d6e33b5f8db1 /bin/ls
+ */
+ if (cp[0] == 's' && cp[1] == 'h' && cp[2] == 'a') {
+ switch (cp[3]) {
+ case '2':
+ if (cp[4] == '2' && cp[5] == '4')
+ digest_type = SUDO_DIGEST_SHA224;
+ else if (cp[4] == '5' && cp[5] == '6')
+ digest_type = SUDO_DIGEST_SHA256;
+ break;
+ case '3':
+ if (cp[4] == '8' && cp[5] == '4')
+ digest_type = SUDO_DIGEST_SHA384;
+ break;
+ case '5':
+ if (cp[4] == '1' && cp[5] == '2')
+ digest_type = SUDO_DIGEST_SHA512;
+ break;
+ }
+ if (digest_type != SUDO_DIGEST_INVALID) {
+ cp += 6;
+ while (isblank((unsigned char)*cp))
+ cp++;
+ if (*cp == ':') {
+ cp++;
+ while (isblank((unsigned char)*cp))
+ cp++;
+ ep = cp;
+ while (*ep != '\0' && !isblank((unsigned char)*ep))
+ ep++;
+ if (*ep != '\0') {
+ digest->digest_type = digest_type;
+ digest->digest_str = estrndup(cp, (size_t)(ep - cp));
+ cp = ep + 1;
+ while (isblank((unsigned char)*cp))
+ cp++;
+ *cmnd = cp;
+ sudo_debug_printf(SUDO_DEBUG_INFO,
+ "%s digest %s for %s",
+ digest_type == SUDO_DIGEST_SHA224 ? "sha224" :
+ digest_type == SUDO_DIGEST_SHA256 ? "sha256" :
+ digest_type == SUDO_DIGEST_SHA384 ? "sha384" :
+ "sha512", digest->digest_str, cp);
+ debug_return_ptr(digest);
+ }
+ }
+ }
+ }
+ debug_return_ptr(NULL);
+}
+