1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/stat.h> 30*0Sstevel@tonic-gate #include <sys/types.h> 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #include <assert.h> 33*0Sstevel@tonic-gate #include <ctype.h> 34*0Sstevel@tonic-gate #include <errno.h> 35*0Sstevel@tonic-gate #include <libintl.h> 36*0Sstevel@tonic-gate #include <libscf.h> 37*0Sstevel@tonic-gate #include <libuutil.h> 38*0Sstevel@tonic-gate #include <limits.h> 39*0Sstevel@tonic-gate #include <md5.h> 40*0Sstevel@tonic-gate #include <pthread.h> 41*0Sstevel@tonic-gate #include <stdio.h> 42*0Sstevel@tonic-gate #include <stdlib.h> 43*0Sstevel@tonic-gate #include <string.h> 44*0Sstevel@tonic-gate #include <strings.h> 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate #include <manifest_hash.h> 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate /* 49*0Sstevel@tonic-gate * Translate a file name to property name. Return an allocated string or NULL 50*0Sstevel@tonic-gate * if realpath() fails. 51*0Sstevel@tonic-gate */ 52*0Sstevel@tonic-gate char * 53*0Sstevel@tonic-gate mhash_filename_to_propname(const char *in) 54*0Sstevel@tonic-gate { 55*0Sstevel@tonic-gate char *out, *cp, *base; 56*0Sstevel@tonic-gate size_t len, piece_len; 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate out = uu_zalloc(PATH_MAX + 1); 59*0Sstevel@tonic-gate if (realpath(in, out) == NULL) { 60*0Sstevel@tonic-gate uu_free(out); 61*0Sstevel@tonic-gate return (NULL); 62*0Sstevel@tonic-gate } 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate base = getenv("PKG_INSTALL_ROOT"); 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate /* 67*0Sstevel@tonic-gate * We copy-shift over the basedir and the leading slash, since it's 68*0Sstevel@tonic-gate * not relevant to when we boot with this repository. 69*0Sstevel@tonic-gate */ 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate cp = out + ((base != NULL)? strlen(base) : 0); 72*0Sstevel@tonic-gate if (*cp == '/') 73*0Sstevel@tonic-gate cp++; 74*0Sstevel@tonic-gate (void) memmove(out, cp, strlen(cp) + 1); 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate len = strlen(out); 77*0Sstevel@tonic-gate if (len > scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) { 78*0Sstevel@tonic-gate /* Use the first half and the second half. */ 79*0Sstevel@tonic-gate piece_len = (scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) - 3) / 2; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate (void) strncpy(out + piece_len, "__", 2); 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate (void) memmove(out + piece_len + 2, out + (len - piece_len), 84*0Sstevel@tonic-gate piece_len + 1); 85*0Sstevel@tonic-gate } 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate /* 88*0Sstevel@tonic-gate * Translate non-property characters to '_', first making sure that 89*0Sstevel@tonic-gate * we don't begin with '_'. 90*0Sstevel@tonic-gate */ 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate if (!isalpha(*out)) 93*0Sstevel@tonic-gate *out = 'A'; 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate for (cp = out + 1; *cp != '\0'; ++cp) { 96*0Sstevel@tonic-gate if (!(isalnum(*cp) || *cp == '_' || *cp == '-')) 97*0Sstevel@tonic-gate *cp = '_'; 98*0Sstevel@tonic-gate } 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate return (out); 101*0Sstevel@tonic-gate } 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate int 104*0Sstevel@tonic-gate mhash_retrieve_entry(scf_handle_t *hndl, const char *name, uchar_t *hash) 105*0Sstevel@tonic-gate { 106*0Sstevel@tonic-gate scf_scope_t *scope; 107*0Sstevel@tonic-gate scf_service_t *svc; 108*0Sstevel@tonic-gate scf_propertygroup_t *pg; 109*0Sstevel@tonic-gate scf_property_t *prop; 110*0Sstevel@tonic-gate scf_value_t *val; 111*0Sstevel@tonic-gate ssize_t szret; 112*0Sstevel@tonic-gate int result = 0; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * In this implementation the hash for name is the opaque value of 116*0Sstevel@tonic-gate * svc:/MHASH_SVC/:properties/name/MHASH_PROP 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate if ((scope = scf_scope_create(hndl)) == NULL || 120*0Sstevel@tonic-gate (svc = scf_service_create(hndl)) == NULL || 121*0Sstevel@tonic-gate (pg = scf_pg_create(hndl)) == NULL || 122*0Sstevel@tonic-gate (prop = scf_property_create(hndl)) == NULL || 123*0Sstevel@tonic-gate (val = scf_value_create(hndl)) == NULL) { 124*0Sstevel@tonic-gate result = -1; 125*0Sstevel@tonic-gate goto out; 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate if (scf_handle_get_local_scope(hndl, scope) < 0) { 129*0Sstevel@tonic-gate result = -1; 130*0Sstevel@tonic-gate goto out; 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate if (scf_scope_get_service(scope, MHASH_SVC, svc) < 0) { 134*0Sstevel@tonic-gate result = -1; 135*0Sstevel@tonic-gate goto out; 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate if (scf_service_get_pg(svc, name, pg) != SCF_SUCCESS) { 139*0Sstevel@tonic-gate result = -1; 140*0Sstevel@tonic-gate goto out; 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate if (scf_pg_get_property(pg, MHASH_PROP, prop) != SCF_SUCCESS) { 144*0Sstevel@tonic-gate result = -1; 145*0Sstevel@tonic-gate goto out; 146*0Sstevel@tonic-gate } 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate if (scf_property_get_value(prop, val) != SCF_SUCCESS) { 149*0Sstevel@tonic-gate result = -1; 150*0Sstevel@tonic-gate goto out; 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate szret = scf_value_get_opaque(val, hash, MHASH_SIZE); 154*0Sstevel@tonic-gate if (szret < 0) { 155*0Sstevel@tonic-gate result = -1; 156*0Sstevel@tonic-gate goto out; 157*0Sstevel@tonic-gate } 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate if (szret != MHASH_SIZE) { 160*0Sstevel@tonic-gate scf_value_destroy(val); 161*0Sstevel@tonic-gate result = -1; 162*0Sstevel@tonic-gate goto out; 163*0Sstevel@tonic-gate } 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate out: 166*0Sstevel@tonic-gate (void) scf_value_destroy(val); 167*0Sstevel@tonic-gate scf_property_destroy(prop); 168*0Sstevel@tonic-gate scf_pg_destroy(pg); 169*0Sstevel@tonic-gate scf_service_destroy(svc); 170*0Sstevel@tonic-gate scf_scope_destroy(scope); 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate return (result); 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate int 176*0Sstevel@tonic-gate mhash_store_entry(scf_handle_t *hndl, const char *name, uchar_t *hash, 177*0Sstevel@tonic-gate char **errstr) 178*0Sstevel@tonic-gate { 179*0Sstevel@tonic-gate scf_scope_t *scope = NULL; 180*0Sstevel@tonic-gate scf_service_t *svc = NULL; 181*0Sstevel@tonic-gate scf_propertygroup_t *pg = NULL; 182*0Sstevel@tonic-gate scf_property_t *prop = NULL; 183*0Sstevel@tonic-gate scf_value_t *val = NULL; 184*0Sstevel@tonic-gate scf_transaction_t *tx = NULL; 185*0Sstevel@tonic-gate scf_transaction_entry_t *e = NULL; 186*0Sstevel@tonic-gate int ret, result = 0; 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate int i; 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate if ((scope = scf_scope_create(hndl)) == NULL || 191*0Sstevel@tonic-gate (svc = scf_service_create(hndl)) == NULL || 192*0Sstevel@tonic-gate (pg = scf_pg_create(hndl)) == NULL || 193*0Sstevel@tonic-gate (prop = scf_property_create(hndl)) == NULL) { 194*0Sstevel@tonic-gate if (errstr != NULL) 195*0Sstevel@tonic-gate *errstr = gettext("Could not create scf objects"); 196*0Sstevel@tonic-gate result = -1; 197*0Sstevel@tonic-gate goto out; 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate if (scf_handle_get_local_scope(hndl, scope) != SCF_SUCCESS) { 201*0Sstevel@tonic-gate if (errstr != NULL) 202*0Sstevel@tonic-gate *errstr = gettext("Could not get local scope"); 203*0Sstevel@tonic-gate result = -1; 204*0Sstevel@tonic-gate goto out; 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate for (i = 0; i < 5; ++i) { 208*0Sstevel@tonic-gate scf_error_t err; 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate if (scf_scope_get_service(scope, MHASH_SVC, svc) == 211*0Sstevel@tonic-gate SCF_SUCCESS) 212*0Sstevel@tonic-gate break; 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) { 215*0Sstevel@tonic-gate if (errstr != NULL) 216*0Sstevel@tonic-gate *errstr = gettext("Could not get manifest hash " 217*0Sstevel@tonic-gate "service"); 218*0Sstevel@tonic-gate result = -1; 219*0Sstevel@tonic-gate goto out; 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate if (scf_scope_add_service(scope, MHASH_SVC, svc) == 223*0Sstevel@tonic-gate SCF_SUCCESS) 224*0Sstevel@tonic-gate break; 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate err = scf_error(); 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate if (err == SCF_ERROR_EXISTS) 229*0Sstevel@tonic-gate /* Try again. */ 230*0Sstevel@tonic-gate continue; 231*0Sstevel@tonic-gate else if (err == SCF_ERROR_PERMISSION_DENIED) { 232*0Sstevel@tonic-gate if (errstr != NULL) 233*0Sstevel@tonic-gate *errstr = gettext("Could not store file hash: " 234*0Sstevel@tonic-gate "permission denied.\n"); 235*0Sstevel@tonic-gate result = -1; 236*0Sstevel@tonic-gate goto out; 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate if (errstr != NULL) 240*0Sstevel@tonic-gate *errstr = gettext("Could not add manifest hash " 241*0Sstevel@tonic-gate "service"); 242*0Sstevel@tonic-gate result = -1; 243*0Sstevel@tonic-gate goto out; 244*0Sstevel@tonic-gate } 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate if (i == 5) { 247*0Sstevel@tonic-gate if (errstr != NULL) 248*0Sstevel@tonic-gate *errstr = gettext("Could not store file hash: " 249*0Sstevel@tonic-gate "service addition contention.\n"); 250*0Sstevel@tonic-gate result = -1; 251*0Sstevel@tonic-gate goto out; 252*0Sstevel@tonic-gate } 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate for (i = 0; i < 5; ++i) { 255*0Sstevel@tonic-gate scf_error_t err; 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate if (scf_service_get_pg(svc, name, pg) == SCF_SUCCESS) 258*0Sstevel@tonic-gate break; 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate if (scf_error() != SCF_ERROR_NOT_FOUND) { 261*0Sstevel@tonic-gate if (errstr != NULL) 262*0Sstevel@tonic-gate *errstr = gettext("Could not get service's " 263*0Sstevel@tonic-gate "hash record)"); 264*0Sstevel@tonic-gate result = -1; 265*0Sstevel@tonic-gate goto out; 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate if (scf_service_add_pg(svc, name, MHASH_PG_TYPE, 269*0Sstevel@tonic-gate MHASH_PG_FLAGS, pg) == SCF_SUCCESS) 270*0Sstevel@tonic-gate break; 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate err = scf_error(); 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate if (err == SCF_ERROR_EXISTS) 275*0Sstevel@tonic-gate /* Try again. */ 276*0Sstevel@tonic-gate continue; 277*0Sstevel@tonic-gate else if (err == SCF_ERROR_PERMISSION_DENIED) { 278*0Sstevel@tonic-gate if (errstr != NULL) 279*0Sstevel@tonic-gate *errstr = gettext("Could not store file hash: " 280*0Sstevel@tonic-gate "permission denied.\n"); 281*0Sstevel@tonic-gate result = -1; 282*0Sstevel@tonic-gate goto out; 283*0Sstevel@tonic-gate } 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate if (errstr != NULL) 286*0Sstevel@tonic-gate *errstr = gettext("Could not store file hash"); 287*0Sstevel@tonic-gate result = -1; 288*0Sstevel@tonic-gate goto out; 289*0Sstevel@tonic-gate } 290*0Sstevel@tonic-gate if (i == 5) { 291*0Sstevel@tonic-gate if (errstr != NULL) 292*0Sstevel@tonic-gate *errstr = gettext("Could not store file hash: " 293*0Sstevel@tonic-gate "property group addition contention.\n"); 294*0Sstevel@tonic-gate result = -1; 295*0Sstevel@tonic-gate goto out; 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate if ((e = scf_entry_create(hndl)) == NULL || 299*0Sstevel@tonic-gate (val = scf_value_create(hndl)) == NULL) { 300*0Sstevel@tonic-gate if (errstr != NULL) 301*0Sstevel@tonic-gate *errstr = gettext("Could not store file hash: " 302*0Sstevel@tonic-gate "permission denied.\n"); 303*0Sstevel@tonic-gate result = -1; 304*0Sstevel@tonic-gate goto out; 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gate ret = scf_value_set_opaque(val, hash, MHASH_SIZE); 308*0Sstevel@tonic-gate assert(ret == SCF_SUCCESS); 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate tx = scf_transaction_create(hndl); 311*0Sstevel@tonic-gate if (tx == NULL) { 312*0Sstevel@tonic-gate if (errstr != NULL) 313*0Sstevel@tonic-gate *errstr = gettext("Could not create transaction"); 314*0Sstevel@tonic-gate result = -1; 315*0Sstevel@tonic-gate goto out; 316*0Sstevel@tonic-gate } 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate do { 319*0Sstevel@tonic-gate if (scf_pg_update(pg) == -1) { 320*0Sstevel@tonic-gate if (errstr != NULL) 321*0Sstevel@tonic-gate *errstr = gettext("Could not update hash " 322*0Sstevel@tonic-gate "entry"); 323*0Sstevel@tonic-gate result = -1; 324*0Sstevel@tonic-gate goto out; 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate if (scf_transaction_start(tx, pg) != SCF_SUCCESS) { 327*0Sstevel@tonic-gate if (scf_error() != SCF_ERROR_PERMISSION_DENIED) { 328*0Sstevel@tonic-gate if (errstr != NULL) 329*0Sstevel@tonic-gate *errstr = gettext("Could not start " 330*0Sstevel@tonic-gate "hash transaction.\n"); 331*0Sstevel@tonic-gate result = -1; 332*0Sstevel@tonic-gate goto out; 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate if (errstr != NULL) 336*0Sstevel@tonic-gate *errstr = gettext("Could not store file hash: " 337*0Sstevel@tonic-gate "permission denied.\n"); 338*0Sstevel@tonic-gate result = -1; 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate scf_transaction_destroy(tx); 341*0Sstevel@tonic-gate (void) scf_entry_destroy(e); 342*0Sstevel@tonic-gate goto out; 343*0Sstevel@tonic-gate } 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate if (scf_transaction_property_new(tx, e, MHASH_PROP, 346*0Sstevel@tonic-gate SCF_TYPE_OPAQUE) != SCF_SUCCESS && 347*0Sstevel@tonic-gate scf_transaction_property_change_type(tx, e, MHASH_PROP, 348*0Sstevel@tonic-gate SCF_TYPE_OPAQUE) != SCF_SUCCESS) { 349*0Sstevel@tonic-gate if (errstr != NULL) 350*0Sstevel@tonic-gate *errstr = gettext("Could not modify hash " 351*0Sstevel@tonic-gate "entry"); 352*0Sstevel@tonic-gate result = -1; 353*0Sstevel@tonic-gate goto out; 354*0Sstevel@tonic-gate } 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate ret = scf_entry_add_value(e, val); 357*0Sstevel@tonic-gate assert(ret == SCF_SUCCESS); 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate ret = scf_transaction_commit(tx); 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate if (ret == 0) 362*0Sstevel@tonic-gate scf_transaction_reset(tx); 363*0Sstevel@tonic-gate } while (ret == 0); 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate if (ret < 0) { 366*0Sstevel@tonic-gate if (scf_error() != SCF_ERROR_PERMISSION_DENIED) { 367*0Sstevel@tonic-gate if (errstr != NULL) 368*0Sstevel@tonic-gate *errstr = gettext("Could not store file hash: " 369*0Sstevel@tonic-gate "permission denied.\n"); 370*0Sstevel@tonic-gate result = -1; 371*0Sstevel@tonic-gate goto out; 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate if (errstr != NULL) 375*0Sstevel@tonic-gate *errstr = gettext("Could not commit transaction"); 376*0Sstevel@tonic-gate result = -1; 377*0Sstevel@tonic-gate } 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate scf_transaction_destroy(tx); 380*0Sstevel@tonic-gate (void) scf_entry_destroy(e); 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate out: 383*0Sstevel@tonic-gate (void) scf_value_destroy(val); 384*0Sstevel@tonic-gate scf_property_destroy(prop); 385*0Sstevel@tonic-gate scf_pg_destroy(pg); 386*0Sstevel@tonic-gate scf_service_destroy(svc); 387*0Sstevel@tonic-gate scf_scope_destroy(scope); 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate return (result); 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate /* 393*0Sstevel@tonic-gate * int mhash_test_file(scf_handle_t *, const char *, uint_t, char **, uchar_t *) 394*0Sstevel@tonic-gate * Test the given filename against the hashed metadata in the repository. 395*0Sstevel@tonic-gate * The behaviours for import and apply are slightly different. For imports, 396*0Sstevel@tonic-gate * if the hash value is absent or different, then the import operation 397*0Sstevel@tonic-gate * continues. For profile application, the operation continues only if the 398*0Sstevel@tonic-gate * hash value for the file is absent. 399*0Sstevel@tonic-gate * 400*0Sstevel@tonic-gate * Return non-zero if we should skip the file because it is unchanged or 401*0Sstevel@tonic-gate * nonexistent. 402*0Sstevel@tonic-gate */ 403*0Sstevel@tonic-gate int 404*0Sstevel@tonic-gate mhash_test_file(scf_handle_t *hndl, const char *file, uint_t is_profile, 405*0Sstevel@tonic-gate char **pnamep, uchar_t *hash) 406*0Sstevel@tonic-gate { 407*0Sstevel@tonic-gate boolean_t do_hash; 408*0Sstevel@tonic-gate struct stat64 st; 409*0Sstevel@tonic-gate char *cp; 410*0Sstevel@tonic-gate char *data; 411*0Sstevel@tonic-gate uchar_t stored_hash[MHASH_SIZE]; 412*0Sstevel@tonic-gate char *pname; 413*0Sstevel@tonic-gate int ret; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* 416*0Sstevel@tonic-gate * In the case where we are doing automated imports, we reduce the UID, 417*0Sstevel@tonic-gate * the GID, the size, and the mtime into a string (to eliminate 418*0Sstevel@tonic-gate * endianness) which we then make opaque as a single MD5 digest. 419*0Sstevel@tonic-gate * 420*0Sstevel@tonic-gate * The previous hash was composed of the inode number, the UID, the file 421*0Sstevel@tonic-gate * size, and the mtime. This formulation was found to be insufficiently 422*0Sstevel@tonic-gate * portable for use in highly replicated deployments. The current 423*0Sstevel@tonic-gate * algorithm will allow matches of this "v1" hash, but always returns 424*0Sstevel@tonic-gate * the effective "v2" hash, such that updates result in the more 425*0Sstevel@tonic-gate * portable hash being used. 426*0Sstevel@tonic-gate * 427*0Sstevel@tonic-gate * If neither calculated digest matches the stored value, we consider 428*0Sstevel@tonic-gate * the test to have failed, implying that some aspect of the manifest 429*0Sstevel@tonic-gate * has changed. 430*0Sstevel@tonic-gate */ 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate cp = getenv("SVCCFG_CHECKHASH"); 433*0Sstevel@tonic-gate do_hash = (cp != NULL && *cp != '\0'); 434*0Sstevel@tonic-gate if (!do_hash) { 435*0Sstevel@tonic-gate *pnamep = NULL; 436*0Sstevel@tonic-gate return (0); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate do 440*0Sstevel@tonic-gate ret = stat64(file, &st); 441*0Sstevel@tonic-gate while (ret < 0 && errno == EINTR); 442*0Sstevel@tonic-gate if (ret < 0) { 443*0Sstevel@tonic-gate return (-1); 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate data = uu_msprintf(MHASH_FORMAT_V2, st.st_uid, st.st_gid, 447*0Sstevel@tonic-gate st.st_size, st.st_mtime); 448*0Sstevel@tonic-gate if (data == NULL) { 449*0Sstevel@tonic-gate return (-1); 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate md5_calc(hash, (uchar_t *)data, strlen(data)); 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate uu_free(data); 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate pname = mhash_filename_to_propname(file); 457*0Sstevel@tonic-gate if (pname == NULL) 458*0Sstevel@tonic-gate return (-1); 459*0Sstevel@tonic-gate 460*0Sstevel@tonic-gate if (mhash_retrieve_entry(hndl, pname, stored_hash) == 0) { 461*0Sstevel@tonic-gate uchar_t hash_v1[MHASH_SIZE]; 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate if (is_profile) { 464*0Sstevel@tonic-gate return (1); 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate /* 468*0Sstevel@tonic-gate * Manifest import. 469*0Sstevel@tonic-gate */ 470*0Sstevel@tonic-gate if (memcmp(hash, stored_hash, MHASH_SIZE) == 0) 471*0Sstevel@tonic-gate return (1); 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate /* 474*0Sstevel@tonic-gate * No match on V2 hash; compare V1 hash. 475*0Sstevel@tonic-gate */ 476*0Sstevel@tonic-gate data = uu_msprintf(MHASH_FORMAT_V1, st.st_ino, st.st_uid, 477*0Sstevel@tonic-gate st.st_size, st.st_mtime); 478*0Sstevel@tonic-gate if (data == NULL) 479*0Sstevel@tonic-gate return (-1); 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate md5_calc(hash_v1, (uchar_t *)data, strlen(data)); 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate uu_free(data); 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate if (memcmp(hash_v1, stored_hash, MHASH_SIZE) == 0) 486*0Sstevel@tonic-gate return (1); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate *pnamep = pname; 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate return (0); 492*0Sstevel@tonic-gate } 493