1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 #pragma ident "%Z%%M% %I% %E% SMI" 40 41 /* 42 * Set secret key on local machine 43 */ 44 #include <stdio.h> 45 #include <rpc/rpc.h> 46 #include <rpc/key_prot.h> 47 #include <nfs/nfs.h> /* to revoke existing creds */ 48 #include <nfs/nfssys.h> 49 #include <string.h> 50 #include <rpcsvc/nis_dhext.h> 51 52 #define ROOTKEY_FILE "/etc/.rootkey" 53 #define ROOTKEY_FILE_BACKUP "/etc/.rootkey.bak" 54 /* Should last until 16384-bit DH keys */ 55 #define MAXROOTKEY_LINE_LEN 4224 56 #define MAXROOTKEY_LEN 4096 57 58 extern int key_setnet_g(); 59 60 static void logout_curr_key(); 61 static int mkrootkey; 62 63 static char *sec_domain = NULL; 64 static char local_domain[MAXNETNAMELEN + 1]; 65 66 /* 67 * fgets is broken in that if it reads a NUL character it will always return 68 * EOF. This replacement can deal with NULs 69 */ 70 static char * 71 fgets_ignorenul(char *s, int n, FILE *stream) 72 { 73 int fildes = fileno(stream); 74 int i = 0; 75 int rs = 0; 76 char c; 77 78 if (fildes < 0) 79 return (NULL); 80 81 while (i < n - 1) { 82 rs = read(fildes, &c, 1); 83 switch (rs) { 84 case 1: 85 break; 86 case 0: 87 /* EOF */ 88 if (i > 0) 89 s[i] = '\0'; 90 return (NULL); 91 break; 92 default: 93 return (NULL); 94 } 95 switch (c) { 96 case '\0': 97 break; 98 case '\n': 99 s[i] = c; 100 s[++i] = '\0'; 101 return (s); 102 default: 103 if (c != '\0') 104 s[i++] = c; 105 } 106 } 107 s[i] = '\0'; 108 return (s); 109 } 110 111 112 /* write unencrypted secret key into root key file */ 113 static void 114 write_rootkey(char *secret, char *flavor, keylen_t keylen, algtype_t algtype) 115 { 116 char line[MAXROOTKEY_LINE_LEN]; 117 char keyent[MAXROOTKEY_LEN]; 118 algtype_t atent; 119 int rootfd, bakfd, hexkeybytes; 120 bool_t lineone = TRUE; 121 bool_t gotit = FALSE; 122 FILE *rootfile, *bakfile; 123 124 unlink(ROOTKEY_FILE_BACKUP); 125 if ((rename(ROOTKEY_FILE, ROOTKEY_FILE_BACKUP)) < 0) { 126 if ((bakfd = creat(ROOTKEY_FILE_BACKUP, 0600)) < 0) { 127 perror("Could not create /etc/.rootkey.bak"); 128 goto rootkey_err; 129 } 130 close(bakfd); 131 } 132 133 if ((rootfd = open(ROOTKEY_FILE, O_WRONLY+O_CREAT, 0600)) < 0) { 134 perror("Could not open /etc/.rootkey for writing"); 135 fprintf(stderr, 136 "Attempting to restore original /etc/.rootkey\n"); 137 (void) rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE); 138 goto rootkey_err; 139 } 140 if (!(rootfile = fdopen(rootfd, "w"))) { 141 perror("Could not open /etc/.rootkey for writing"); 142 fprintf(stderr, 143 "Attempting to restore original /etc/.rootkey\n"); 144 close(rootfd); 145 unlink(ROOTKEY_FILE); 146 rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE); 147 goto rootkey_err; 148 } 149 if (!(bakfile = fopen(ROOTKEY_FILE_BACKUP, "r"))) { 150 perror("Could not open /etc/.rootkey.bak for reading"); 151 fprintf(stderr, 152 "Attempting to restore original /etc/.rootkey\n"); 153 (void) fclose(rootfile); 154 unlink(ROOTKEY_FILE); 155 rename(ROOTKEY_FILE_BACKUP, ROOTKEY_FILE); 156 goto rootkey_err; 157 } 158 159 hexkeybytes = ((keylen + 7) / 8) * 2; 160 161 while (fgets_ignorenul(line, MAXROOTKEY_LINE_LEN, bakfile)) { 162 if (sscanf(line, "%s %d", keyent, &atent) < 2) { 163 /* 164 * No encryption algorithm found in the file 165 * (atent) so default to DES. 166 */ 167 atent = AUTH_DES_ALGTYPE; 168 } 169 /* 170 * 192-bit keys always go on the first line 171 */ 172 if (lineone) { 173 lineone = FALSE; 174 if (keylen == 192) { 175 gotit = TRUE; 176 fprintf(rootfile, "%s\n", secret); 177 } else 178 fprintf(rootfile, "%s", line); 179 (void) fflush(rootfile); 180 } else { 181 if ((strlen(keyent) == hexkeybytes) && 182 (atent == algtype)) { 183 /* 184 * Silently remove lines with the same 185 * keylen/algtype 186 */ 187 if (gotit) 188 continue; 189 else 190 gotit = TRUE; 191 192 fprintf(rootfile, "%s %d\n", secret, algtype); 193 } else 194 fprintf(rootfile, "%s", line); 195 (void) fflush(rootfile); 196 } 197 } 198 199 /* Append key to rootkey file */ 200 if (!gotit) { 201 if (keylen == 192) 202 fprintf(rootfile, "%s\n", secret); 203 else { 204 if (lineone) 205 fprintf(rootfile, "\n"); 206 fprintf(rootfile, "%s %d\n", secret, algtype); 207 } 208 } 209 (void) fflush(rootfile); 210 fclose(rootfile); 211 fclose(bakfile); 212 unlink(ROOTKEY_FILE_BACKUP); 213 if (keylen == 192) 214 fprintf(stderr, "Wrote secret key into %s\n", ROOTKEY_FILE); 215 else 216 fprintf(stderr, "Wrote %s key into %s\n", flavor, 217 ROOTKEY_FILE); 218 return; 219 220 rootkey_err: 221 fprintf(stderr, "WARNING: Could not write %s key to /etc/.rootkey\n", 222 flavor); 223 } 224 225 /* Perform AUTH_DES keylogin */ 226 static int 227 oldkeylogin(char *fullname, char *pass) 228 { 229 char secret[HEXKEYBYTES+1]; 230 struct key_netstarg netst; 231 232 if (getsecretkey(fullname, secret, pass) == 0) { 233 fprintf(stderr, "Could not find %s's secret key\n", 234 fullname); 235 if (sec_domain && *sec_domain && 236 strcasecmp(sec_domain, local_domain)) { 237 fprintf(stderr, 238 "The system default domain '%s' is different from the Secure RPC\n\ 239 domain %s where the key is stored. The Secure RPC domainname is\n\ 240 defined by the directory object stored in the /var/nis/NIS_COLD_START file.\n\ 241 If you need to change this Secure RPC domainname, please use the nisinit(1M)\n\ 242 command with the `-k` option.\n", local_domain, sec_domain); 243 } else { 244 fprintf(stderr, 245 "Make sure the secret key is stored in domain %s\n", 246 local_domain); 247 } 248 return (1); 249 } 250 251 if (secret[0] == 0) { 252 fprintf(stderr, "Password incorrect for %s\n", 253 fullname); 254 return (1); 255 } 256 /* revoke any existing (lingering) credentials... */ 257 logout_curr_key(); 258 259 memcpy(netst.st_priv_key, secret, HEXKEYBYTES); 260 memset(secret, 0, HEXKEYBYTES); 261 262 netst.st_pub_key[0] = 0; 263 netst.st_netname = strdup(fullname); 264 265 /* do actual key login */ 266 if (key_setnet(&netst) < 0) { 267 fprintf(stderr, "Could not set %s's secret key\n", 268 fullname); 269 fprintf(stderr, "May be the keyserv is down?\n"); 270 if (mkrootkey == 0) /* nothing else to do */ 271 return (1); 272 } 273 274 /* write unencrypted secret key into root key file */ 275 if (mkrootkey) 276 write_rootkey(netst.st_priv_key, "des", 192, 0); 277 278 return (0); 279 } 280 281 /* 282 * Revokes the existing credentials for Secure-RPC and Secure-NFS. 283 * This should only be called if the user entered the correct password; 284 * sorta like the way "su" doesn't force a login if you enter the wrong 285 * password. 286 */ 287 288 static void 289 logout_curr_key() 290 { 291 static char secret[HEXKEYBYTES + 1]; 292 struct nfs_revauth_args nra; 293 294 /* 295 * try to revoke the existing key/credentials, assuming 296 * one exists. this will effectively mark "stale" any 297 * cached credientials... 298 */ 299 if (key_setsecret(secret) < 0) { 300 return; 301 } 302 303 /* 304 * it looks like a credential already existed, so try and 305 * revoke any lingering Secure-NFS privledges. 306 */ 307 308 nra.authtype = AUTH_DES; 309 nra.uid = getuid(); 310 311 (void) _nfssys(NFS_REVAUTH, &nra); 312 } 313 314 void 315 usage(cmd) 316 char *cmd; 317 { 318 fprintf(stderr, "usage: %s [-r]\n", cmd); 319 exit(1); 320 } 321 322 323 int 324 main(int argc, char *argv[]) 325 { 326 char secret[4096]; 327 char fullname[MAXNETNAMELEN + 1]; 328 char *getpass(); 329 char *pass; 330 int i = 0; 331 mechanism_t **mechlist; 332 333 if (argc == 1) 334 mkrootkey = 0; 335 else if (argc == 2 && (strcmp(argv[1], "-r") == 0)) { 336 if (geteuid() != 0) { 337 fprintf(stderr, "Must be root to use -r option.\n"); 338 exit(1); 339 } 340 mkrootkey = 1; 341 } else 342 usage(argv[0]); 343 344 if (getnetname(fullname) == 0) { 345 fprintf(stderr, "Could not generate netname\n"); 346 exit(1); 347 } 348 sec_domain = strdup(strchr(fullname, '@') + 1); 349 getdomainname(local_domain, MAXNETNAMELEN); 350 351 if (!(pass = getpass("Password:"))) 352 exit(1); 353 354 if (mechlist = __nis_get_mechanisms(FALSE)) { 355 while (mechlist[i]) { 356 char *alias; 357 358 if (AUTH_DES_COMPAT_CHK(mechlist[i])) { 359 (void) oldkeylogin(fullname, pass); 360 i++; 361 continue; 362 } 363 364 if (VALID_ALIAS(mechlist[i]->alias)) 365 alias = mechlist[i]->alias; 366 else 367 alias = ""; 368 369 if (getsecretkey_g(fullname, mechlist[i]->keylen, 370 mechlist[i]->algtype, secret, 371 (((mechlist[i]->keylen / 7) + 372 8) * 2) + 1, pass) == 0) { 373 fprintf(stderr, 374 "WARNING: Could not find %s's %s secret key\n", 375 fullname, alias); 376 i++; 377 continue; 378 } 379 380 if (secret[0] == 0) { 381 fprintf(stderr, 382 "Password incorrect for %s's %s key.\n", 383 fullname, alias); 384 i++; 385 continue; 386 } 387 388 if (key_setnet_g(fullname, secret, 389 mechlist[i]->keylen, NULL, 0, 390 mechlist[i]->algtype) < 0) { 391 fprintf(stderr, 392 "Could not set %s's %s secret key\n", 393 fullname, alias); 394 fprintf(stderr, 395 "May be the keyserv is down?\n"); 396 exit(1); 397 } 398 399 if (mkrootkey) 400 write_rootkey(secret, mechlist[i]->alias, 401 mechlist[i]->keylen, 402 mechlist[i]->algtype); 403 i++; 404 } 405 } else 406 exit(oldkeylogin(fullname, pass)); 407 408 return (0); 409 } 410