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