"REQUIRES_HW_AUTH", /* 0x00000100 */
"REQUIRES_PWCHANGE", /* 0x00000200 */
"UNKNOWN_0x00000400", /* 0x00000400 */
- "UNKNOWN_0x00000800, /* 0x00000800 */
+ "UNKNOWN_0x00000800", /* 0x00000800 */
"DISALLOW_SVR", /* 0x00001000 */
"PWCHANGE_SERVICE" /* 0x00002000 */
};
char *getenv();
struct passwd *getpwuid();
int exit_status = 0;
+char *def_realm = NULL;
void usage()
{
exit(1);
}
+/* this is a wrapper to go around krb5_parse_principal so we can set
+ the default realm up properly */
+krb5_error_code kadmin_parse_name(name, principal)
+ char *name;
+ krb5_principal *principal;
+{
+ char *cp, *fullname;
+ krb5_error_code retval;
+
+ /* assumes def_realm is initialized! */
+ fullname = (char *)malloc(strlen(name) + 1 + strlen(def_realm) + 1);
+ if (fullname == NULL)
+ return ENOMEM;
+ strcpy(fullname, name);
+ cp = strchr(fullname, '@');
+ while (cp) {
+ if (cp - fullname && *(cp - 1) != '\\')
+ break;
+ else
+ cp = strchr(cp, '@');
+ }
+ if (cp == NULL) {
+ strcat(fullname, "@");
+ strcat(fullname, def_realm);
+ }
+ retval = krb5_parse_name(fullname, principal);
+ free(fullname);
+ return retval;
+}
+
char *kadmin_startup(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
- char *realmname = NULL, *princstr = NULL, *keytab = NULL, *query = NULL;
- char *luser;
+ char *princstr = NULL, *keytab = NULL, *query = NULL;
+ char *luser, *canon, *cp;
int optchar, freeprinc = 0;
struct passwd *pw;
ovsec_kadm_ret_t retval;
krb5_ccache cc;
krb5_principal princ;
-
+
while ((optchar = getopt(argc, argv, "r:p:k:q:")) != EOF) {
switch (optchar) {
case 'r':
- realmname = optarg;
+ def_realm = optarg;
break;
case 'p':
princstr = optarg;
usage();
}
}
+ if (def_realm == NULL && krb5_get_default_realm(&def_realm)) {
+ if (freeprinc)
+ free(princstr);
+ fprintf(stderr, "kadmin: unable to get default realm\n");
+ exit(1);
+ }
if (princstr == NULL) {
if (!krb5_cc_default(&cc) && !krb5_cc_get_principal(cc, &princ)) {
- princstr =
- (char *)malloc(krb5_princ_component(princ, 0)->length +
- 7 /* "/admin@" */ +
- krb5_princ_realm(princ)->length + 1);
+ char *realm = NULL;
+ if (krb5_unparse_name(princ, &canon)) {
+ fprintf(stderr,
+ "kadmin: unable to canonicalize principal\n");
+ krb5_free_principal(princ);
+ exit(1);
+ }
+ /* strip out realm of principal if it's there */
+ realm = strchr(canon, '@');
+ while (realm) {
+ if (realm - canon && *(realm - 1) != '\\')
+ break;
+ else
+ realm = strchr(realm, '@');
+ }
+ if (realm)
+ *realm++ = '\0';
+ cp = strchr(canon, '/');
+ while (cp) {
+ if (cp - canon && *(cp - 1) != '\\')
+ break;
+ else
+ cp = strchr(cp, '/');
+ }
+ if (cp != NULL)
+ *cp = '\0';
+ princstr = (char*)malloc(strlen(canon) + 6 /* "/admin" */ +
+ (realm ? 1 + strlen(realm) : 0) + 1);
if (princstr == NULL) {
fprintf(stderr, "kadmin: out of memory\n");
exit(1);
}
- /* XXX assuming no nulls in principal */
- strncpy(princstr, krb5_princ_component(princ, 0)->data,
- krb5_princ_component(princ, 0)->length);
- princstr[krb5_princ_component(princ, 0)->length] = '\0';
- strcat(princstr, "/admin@");
- strncat(princstr, krb5_princ_realm(princ)->data,
- krb5_princ_realm(princ)->length);
+ strcpy(princstr, canon);
+ strcat(princstr, "/admin");
+ if (realm) {
+ strcat(princstr, "@");
+ strcat(princstr, realm);
+ }
+ free(canon);
krb5_free_principal(princ);
freeprinc++;
} else if (luser = getenv("USER")) {
- princstr = malloc(strlen(luser) + 6 /* "/admin" */ + 1);
+ princstr = malloc(strlen(luser) + 7 /* "/admin@" */
+ + strlen(def_realm) + 1);
if (princstr == NULL) {
fprintf(stderr, "kadmin: out of memory\n");
exit(1);
}
strcpy(princstr, luser);
strcat(princstr, "/admin");
+ strcat(princstr, "@");
+ strcat(princstr, def_realm);
freeprinc++;
} else if (pw = getpwuid(getuid())) {
- princstr = malloc(strlen(pw->pw_name) + 6 /* "/admin" */ + 1);
+ princstr = malloc(strlen(pw->pw_name) + 7 /* "/admin@" */
+ + strlen(def_realm) + 1);
if (princstr == NULL) {
fprintf(stderr, "kadmin: out of memory\n");
exit(1);
}
strcpy(princstr, pw->pw_name);
- strcat(princstr, "/admin");
+ strcat(princstr, "/admin@");
+ strcat(princstr, def_realm);
freeprinc++;
} else {
fprintf(stderr, "kadmin: unable to figure out a principal name\n");
exit(1);
}
}
-
retval = ovsec_kadm_init(princstr, NULL, OVSEC_KADM_ADMIN_SERVICE,
- realmname);
+ def_realm);
if (freeprinc)
free(princstr);
if (retval) { /* assume kadm_init does init_ets() */
krb5_principal princ;
char *canon;
char reply[5];
-
+
if (argc < 2 || argc > 3) {
fprintf(stderr, "delete_principal: wrong number of arguments\n");
return;
fprintf(stderr, "delete_principal: bad arguments\n");
return;
}
- retval = krb5_parse_name(argv[argc - 1], &princ);
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
if (retval) {
com_err("delete_principal", retval, "while parsing principal name");
return;
char *oldcanon, *newcanon;
char reply[5];
ovsec_kadm_ret_t retval;
-
+
if (argc < 3 || argc > 4) {
fprintf(stderr, "rename_principal: wrong number of arguments\n");
return;
fprintf(stderr, "rename_principal: bad arguments\n");
return;
}
- retval = krb5_parse_name(argv[argc - 2], &oldprinc);
+ retval = kadmin_parse_name(argv[argc - 2], &oldprinc);
if (retval) {
com_err("rename_principal", retval, "while parsing old principal");
return;
}
- retval = krb5_parse_name(argv[argc - 1], &newprinc);
+ retval = kadmin_parse_name(argv[argc - 1], &newprinc);
if (retval) {
krb5_free_principal(oldprinc);
com_err("rename_principal", retval, "while parsing new principal");
}
if (argc == 3) {
printf("Are you sure you want to rename the principal \"%s\" to \"%s\"? (yes/no): ",
- oldcanon, newacnon);
+ oldcanon, newcanon);
fgets(reply, sizeof (reply), stdin);
if (strcmp("yes\n", reply)) {
fprintf(stderr,
free(oldcanon);
return;
}
- fprintf("Principal \"%s\" renamed to \"%s\".\nMake sure that you have removed \"%s\" from all ACLs before reusing.\n",
- oldcanon, newcanon, newcanon);
+ printf("Principal \"%s\" renamed to \"%s\".\nMake sure that you have removed \"%s\" from all ACLs before reusing.\n",
+ oldcanon, newcanon, newcanon);
return;
}
static char prompt1[1024], prompt2[1024];
char *canon;
krb5_principal princ;
-
+
if (argc < 2 || argc > 4) {
fprintf(stderr, "change_password: too many arguments\n");
return;
}
- retval = krb5_parse_name(argv[argc - 1], &princ);
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
if (retval) {
com_err("change_password", retval, "while parsing principal name");
return;
return;
} else if (argc == 2) {
int i = sizeof (newpw) - 1;
-
+
sprintf(prompt1, "Enter password for principal \"%.900s\": ",
argv[1]);
sprintf(prompt2,
free(canon);
return;
}
- printf("Password for \"%s\" changed.", canon);
+ printf("Password for \"%s\" changed.\n", canon);
free(canon);
return;
}
*mask = 0;
*pass = NULL;
ftime(&now);
- for (i = 1; i < argc - 2; i++) {
+ for (i = 1; i < argc - 1; i++) {
if (strlen(argv[i]) == 7 &&
!strcmp("-expire", argv[i])) {
if (++i > argc - 2)
if (++i > argc - 2)
return -1;
else {
- oprinc->max_life = get_date(argv[i], now);
+ oprinc->max_life = get_date(argv[i], now) - now.time;
*mask |= OVSEC_KADM_MAX_LIFE;
continue;
}
if (++i > argc - 2)
return -1;
else {
- pass = argv[i];
+ *pass = argv[i];
continue;
}
}
}
}
}
+ return -1;
}
if (i != argc - 1) {
- fprintf("%s: parser lost count!\n", caller);
+ fprintf(stderr, "%s: parser lost count!\n", caller);
return -1;
}
- retval = krb5_parse_name(argv[i], &oprinc->principal);
+ retval = kadmin_parse_name(argv[i], &oprinc->principal);
if (retval) {
com_err(caller, retval, "while parsing principal");
return -1;
}
- *mask |= OVSEC_KADM_PRINCIPAL;
return 0;
}
u_int32 mask;
char *pass, *canon;
krb5_error_code retval;
-
+ static char newpw[1024];
+ static char prompt1[1024], prompt2[1024];
+
+ princ.attributes = 0;
if (kadmin_parse_princ_args(argc, argv,
- &princ, &mask, pass, "add_principal")) {
+ &princ, &mask, &pass, "add_principal")) {
fprintf(stderr, "add_principal: bad arguments\n");
return;
}
- retval = krb5_unparse_name(princ->principal, &canon);
+ retval = krb5_unparse_name(princ.principal, &canon);
if (retval) {
com_err("add_principal",
retval, "while canonicalizing principal");
- krb5_free_principal(princ->principal);
+ krb5_free_principal(princ.principal);
return;
}
+ if (pass == NULL) {
+ int i = sizeof (newpw) - 1;
+
+ sprintf(prompt1, "Enter password for principal \"%.900s\": ",
+ argv[1]);
+ sprintf(prompt2,
+ "Re-enter password for principal \"%.900s\": ",
+ argv[1]);
+ retval = krb5_read_password(prompt1, prompt2,
+ newpw, &i);
+ if (retval) {
+ com_err("add_principal", retval,
+ "while reading password for \"%s\".", canon);
+ free(canon);
+ krb5_free_principal(princ.principal);
+ return;
+ }
+ pass = newpw;
+ }
+ mask |= OVSEC_KADM_PRINCIPAL;
retval = ovsec_kadm_create_principal(&princ, mask, pass);
- krb5_free_principal(princ->principal);
+ krb5_free_principal(princ.principal);
if (retval) {
com_err("add_principal", retval, "while creating \"%s\".",
canon);
u_int32 mask;
krb5_error_code retval;
char *pass, *canon;
-
+
+ princ.attributes = 0;
if (kadmin_parse_princ_args(argc, argv,
- &princ, &mask, pass, "modify_principal")) {
+ &princ, &mask, &pass, "modify_principal")) {
fprintf(stderr, "modify_principal: bad arguments\n");
return;
}
- retval = krb5_unparse_name(princ->principal, &canon);
+ retval = krb5_unparse_name(princ.principal, &canon);
if (retval) {
com_err("modify_principal", retval,
"while canonicalizing principal");
- krb5_free_principal(princ->principal);
+ krb5_free_principal(princ.principal);
return;
}
retval = ovsec_kadm_modify_principal(&princ, mask);
krb5_error_code retval;
char *canon, *modcanon;
int i;
-
+
if (argc < 2 || argc > 3) {
fprintf(stderr, "get_principal: wrong number of arguments\n");
return;
}
if (argc == 3 &&
- (strlen(argv[1]) == 6 ? !strcmp("-terse", argv[1]) : 1)) {
+ (strlen(argv[1]) == 6 ? strcmp("-terse", argv[1]) : 1)) {
fprintf(stderr, "get_principal: bad arguments\n");
return;
}
- retval = krb5_parse_name(argv[argc - 1], &princ);
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
if (retval) {
com_err("get_principal", retval, "while parsing principal");
return;
if (retval) {
com_err("get_principal", retval, "while retrieving \"%s\".", canon);
free(canon);
- krb5_free_principal(princ);
return;
}
- retval = krb5_unparse_name(princ->mod_name, &modcanon);
+ retval = krb5_unparse_name(dprinc->mod_name, &modcanon);
if (retval) {
com_err("get_principal", retval, "while unparsing modname");
ovsec_kadm_free_principal_ent(dprinc);
free(canon);
- krb5_free_principal(princ);
return;
}
if (argc == 2) {
printf("Attributes: ");
for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) {
if (dprinc->attributes & (krb5_flags) 1 << i)
- printf("%s%s", i ? ", " : "", prflags[i]);
+ printf(" %s", prflags[i]);
}
printf("\n");
printf("Key version: %d\n", dprinc->kvno);
free(modcanon);
ovsec_kadm_free_principal_ent(dprinc);
free(canon);
- krb5_free_principal(princ);
+}
+
+int kadmin_parse_policy_args(argc, argv, policy, mask, caller)
+ int argc;
+ char *argv[];
+ ovsec_kadm_policy_ent_t policy;
+ u_int32 *mask;
+ char *caller;
+{
+ int i;
+ struct timeb now;
+ krb5_error_code retval;
+
+ ftime(&now);
+ *mask = 0;
+ for (i = 1; i < argc - 1; i++) {
+ if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-maxlife")) {
+ if (++i > argc -2)
+ return -1;
+ else {
+ policy->pw_max_life = get_date(argv[i], now) - now.time;
+ *mask |= OVSEC_KADM_PW_MAX_LIFE;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-minlife")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_min_life = get_date(argv[i], now) - now.time;
+ *mask |= OVSEC_KADM_PW_MIN_LIFE;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 10 &&
+ !strcmp(argv[i], "-minlength")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_min_length = atoi(argv[i]);
+ *mask |= OVSEC_KADM_PW_MIN_LENGTH;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 11 &&
+ !strcmp(argv[i], "-minclasses")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_min_classes = atoi(argv[i]);
+ *mask |= OVSEC_KADM_PW_MIN_CLASSES;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-history")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_history_num = atoi(argv[i]);
+ *mask |= OVSEC_KADM_PW_HISTORY_NUM;
+ continue;
+ }
+ } else
+ return -1;
+ }
+ if (i != argc -1) {
+ fprintf(stderr, "%s: parser lost count!\n", caller);
+ return -1;
+ } else
+ return 0;
+}
+
+void kadmin_addpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ u_int32 mask;
+ ovsec_kadm_policy_ent_rec policy;
+
+ if (kadmin_parse_policy_args(argc, argv, &policy, &mask, "add_policy")) {
+ fprintf(stderr, "add_policy: bad arguments\n");
+ return;
+ } else {
+ policy.policy = argv[argc - 1];
+ mask |= OVSEC_KADM_POLICY;
+ retval = ovsec_kadm_create_policy(&policy, mask);
+ if (retval) {
+ com_err("add_policy", retval, "while creating policy \"%s\".",
+ policy.policy);
+ return;
+ }
+ }
+ return;
+}
+
+void kadmin_modpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ u_int32 mask;
+ ovsec_kadm_policy_ent_rec policy;
+
+ if (kadmin_parse_policy_args(argc, argv, &policy, &mask,
+ "modify_policy")) {
+ fprintf(stderr, "modify_policy: bad arguments\n");
+ return;
+ } else {
+ policy.policy = argv[argc - 1];
+ retval = ovsec_kadm_modify_policy(&policy, mask);
+ if (retval) {
+ com_err("modify_policy", retval, "while modifying policy \"%s\".",
+ policy.policy);
+ return;
+ }
+ }
+ return;
+}
+
+void kadmin_delpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ char reply[5];
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "delete_policy: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-force", argv[1]) : 1)) {
+ fprintf(stderr, "delete_policy: bad arguments\n");
+ return;
+ }
+ if (argc == 2) {
+ printf("Are you sure you want to delete the policy \"%s\"? (yes/no): ", argv[1]);
+ fgets(reply, sizeof (reply), stdin);
+ if (strcmp("yes\n", reply)) {
+ fprintf(stderr, "Policy \"%s\" not deleted.\n", argv[1]);
+ return;
+ }
+ }
+ retval = ovsec_kadm_delete_policy(argv[argc - 1]);
+ if (retval) {
+ com_err("delete_policy:", retval, "while deleting policy \"%s\"",
+ argv[argc - 1]);
+ return;
+ }
+ return;
+}
+
+void kadmin_getpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ ovsec_kadm_policy_ent_t policy;
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "get_policy: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-terse", argv[1]) : 1)) {
+ fprintf(stderr, "get_policy: bad arguments\n");
+ return;
+ }
+ retval = ovsec_kadm_get_policy(argv[argc - 1], &policy);
+ if (retval) {
+ com_err("get_policy", retval, "while retrieving policy \"%s\".",
+ argv[argc - 1]);
+ return;
+ }
+ if (argc == 2) {
+ printf("Policy: %s\n", policy->policy);
+ printf("Maximum password life: %d\n", policy->pw_max_life);
+ printf("Minimum password life: %d\n", policy->pw_min_life);
+ printf("Minimum password length: %d\n", policy->pw_min_length);
+ printf("Minimum number of password character classes: %d\n",
+ policy->pw_min_classes);
+ printf("Number of old keys kept: %d\n", policy->pw_history_num);
+ printf("Reference count: %d\n", policy->policy_refcnt);
+ } else {
+ printf("\"%s\"\t%d\t%d\t%d\t%d\t%d\t%d\n",
+ policy->policy, policy->pw_max_life, policy->pw_min_life,
+ policy->pw_min_length, policy->pw_min_classes,
+ policy->pw_history_num, policy->policy_refcnt);
+ }
+ ovsec_kadm_free_policy_ent(policy);
+ return;
+}
+
+kadmin_getprivs(argc, argv)
+ int argc;
+ char *argv[];
+{
+ static char *privs[] = {"GET", "ADD", "MODIFY", "DELETE"};
+ krb5_error_code retval;
+ int i;
+ u_int32 plist;
+
+ if (argc != 1) {
+ fprintf(stderr, "get_privs: bad arguments\n");
+ return;
+ }
+ retval = ovsec_kadm_get_privs(&plist);
+ if (retval) {
+ com_err("get_privs", retval, "while retrieving privileges");
+ return;
+ }
+ printf("current privileges:");
+ for (i = 0; i < sizeof (privs) / sizeof (char *); i++) {
+ if (plist & 1 << i)
+ printf(" %s", privs[i]);
+ }
+ printf("\n");
+ return;
}
--- /dev/null
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define MEMMOVE
+
+/* based on @(#)bcopy.c 5.11 (Berkeley) 6/21/91 */
+
+#include <krb5/osconf.h>
+#include <krb5/config.h>
+#ifdef USE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * sizeof(word) MUST BE A POWER OF TWO
+ * SO THAT wmask BELOW IS ALL ONES
+ */
+typedef int word; /* "word" used for optimal copy speed */
+
+#define wsize sizeof(word)
+#define wmask (wsize - 1)
+
+/*
+ * Copy a block of memory, handling overlap.
+ * This is the routine that actually implements
+ * (the portable versions of) bcopy, memcpy, and memmove.
+ */
+#ifdef MEMCOPY
+void *
+memcpy(dst0, src0, length)
+#else
+#ifdef MEMMOVE
+void *
+memmove(dst0, src0, length)
+#else
+void
+bcopy(src0, dst0, length)
+#endif
+#endif
+ void *dst0;
+ const void *src0;
+ register size_t length;
+{
+ register char *dst = dst0;
+ register const char *src = src0;
+ register size_t t;
+
+ if (length == 0 || dst == src) /* nothing to do */
+ goto done;
+
+ /*
+ * Macros: loop-t-times; and loop-t-times, t>0
+ */
+#define TLOOP(s) if (t) TLOOP1(s)
+#define TLOOP1(s) do { s; } while (--t)
+
+ if ((unsigned long)dst < (unsigned long)src) {
+ /*
+ * Copy forward.
+ */
+ t = (int)src; /* only need low bits */
+ if ((t | (int)dst) & wmask) {
+ /*
+ * Try to align operands. This cannot be done
+ * unless the low bits match.
+ */
+ if ((t ^ (int)dst) & wmask || length < wsize)
+ t = length;
+ else
+ t = wsize - (t & wmask);
+ length -= t;
+ TLOOP1(*dst++ = *src++);
+ }
+ /*
+ * Copy whole words, then mop up any trailing bytes.
+ */
+ t = length / wsize;
+ TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
+ t = length & wmask;
+ TLOOP(*dst++ = *src++);
+ } else {
+ /*
+ * Copy backwards. Otherwise essentially the same.
+ * Alignment works as before, except that it takes
+ * (t&wmask) bytes to align, not wsize-(t&wmask).
+ */
+ src += length;
+ dst += length;
+ t = (int)src;
+ if ((t | (int)dst) & wmask) {
+ if ((t ^ (int)dst) & wmask || length <= wsize)
+ t = length;
+ else
+ t &= wmask;
+ length -= t;
+ TLOOP1(*--dst = *--src);
+ }
+ t = length / wsize;
+ TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
+ t = length & wmask;
+ TLOOP(*--dst = *--src);
+ }
+done:
+#if defined(MEMCOPY) || defined(MEMMOVE)
+ return (dst0);
+#else
+ return;
+#endif
+}