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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
40 * Administrative tool to add a new user to the publickey database
45 #include <rpc/key_prot.h>
46 #include <rpcsvc/ypclnt.h>
53 #include <sys/resource.h>
55 #include <rpcsvc/nis.h>
57 #define MAXMAPNAMELEN 256
58 #define MAXPASSWD 256 /* max significant characters in password */
63 #define DESCREDPASSLEN sizeof (des_block)
67 extern int __getnetnamebyuid();
68 extern int self_check(char *name
);
70 #define local_host(host_name) self_check(host_name)
74 static char *get_password();
75 static char *basename();
76 static char SHELL
[] = "/bin/sh";
77 static char YPDBPATH
[] = "/var/yp";
78 static char PKMAP
[] = "publickey.byname";
79 static char UPDATEFILE
[] = "updaters";
80 static char PKFILE
[] = "/etc/publickey";
81 static void usage(void);
84 main(int argc
, char *argv
[])
86 char name
[MAXNETNAMELEN
+ 1];
87 char public[HEXKEYBYTES
+ 1];
88 char secret
[HEXKEYBYTES
+ 1];
89 char crypt1
[HEXKEYBYTES
+ KEYCHECKSUMSIZE
+ 1];
91 char *pass
, *target_host
= NULL
,
92 *username
= NULL
, *pk_service
= NULL
;
93 char short_pass
[DESCREDPASSLEN
+ 1];
95 NCONF_HANDLE
*nc_handle
;
96 struct netconfig
*nconf
;
97 struct nd_hostserv service
;
98 struct nd_addrlist
*addrs
;
102 char host_pname
[NIS_MAXNAMELEN
];
104 program_name
= argv
[0];
105 while ((c
= getopt(argc
, argv
, "s:u:h:")) != -1) {
108 if (pk_service
== NULL
)
114 if (username
|| target_host
)
119 if (username
|| target_host
)
121 target_host
= optarg
;
128 if (optind
< argc
|| (username
== 0 && target_host
== 0)) {
132 if ((pk_database
= get_pk_source(pk_service
)) == 0)
135 if (geteuid() != 0) {
136 (void) fprintf(stderr
, "Must be superuser to run %s\n",
142 pw
= getpwnam(username
);
144 (void) fprintf(stderr
, "%s: unknown user: '%s'\n",
145 program_name
, username
);
150 if (! getnetname(name
)) {
151 (void) fprintf(stderr
,
152 "%s: could not get the equivalent netname for %s\n",
153 program_name
, username
);
156 if (gethostname(host_pname
, NIS_MAXNAMELEN
)
158 (void) fprintf(stderr
,
159 "%s: could not get the hostname for %s\n",
160 program_name
, username
);
163 target_host
= host_pname
;
165 if (__getnetnamebyuid(name
, uid
) == 0) {
166 (void) fprintf(stderr
,
167 "%s: could not get the equivalent netname for %s\n",
168 program_name
, username
);
172 /* -h hostname option */
173 service
.h_host
= target_host
;
174 service
.h_serv
= NULL
;
176 /* verify if this is a valid hostname */
177 nc_handle
= setnetconfig();
178 if (nc_handle
== NULL
) {
179 /* fails to open netconfig file */
180 (void) fprintf(stderr
,
181 "%s: failed in routine setnetconfig()\n",
185 while (nconf
= getnetconfig(nc_handle
)) {
186 /* check to see if hostname exists for this transport */
187 if ((netdir_getbyname(nconf
, &service
, &addrs
) == 0) &&
188 (addrs
->n_cnt
!= 0)) {
189 /* at least one valid address */
194 endnetconfig(nc_handle
);
196 (void) fprintf(stderr
, "%s: unknown host: %s\n",
197 program_name
, target_host
);
200 (void) host2netname(name
, target_host
, NULL
);
204 (void) fprintf(stdout
, "Adding new key for %s.\n", name
);
205 pass
= get_password(uid
, target_host
, username
);
210 (void) strlcpy(short_pass
, pass
, sizeof (short_pass
));
211 (void) __gen_dhkeys(public, secret
, short_pass
);
213 (void) memcpy(crypt1
, secret
, HEXKEYBYTES
);
214 (void) memcpy(crypt1
+ HEXKEYBYTES
, secret
, KEYCHECKSUMSIZE
);
215 crypt1
[HEXKEYBYTES
+ KEYCHECKSUMSIZE
] = 0;
216 xencrypt(crypt1
, short_pass
);
218 if (status
= setpublicmap(name
, public, crypt1
, pk_database
,
220 switch (pk_database
) {
222 (void) fprintf(stderr
,
223 "%s: unable to update NIS database (%u): %s\n",
224 program_name
, status
,
225 yperr_string(status
));
228 (void) fprintf(stderr
,
229 "%s: hence, unable to update publickey database\n",
233 (void) fprintf(stderr
,
234 "%s: could not update unknown database: %d\n",
235 program_name
, pk_database
);
243 * Set the entry in the public key file
246 setpublicmap(name
, public, secret
, database
, pw
)
253 char pkent
[HEXKEYBYTES
+ HEXKEYBYTES
+ KEYCHECKSUMSIZE
+ 2];
256 char hostname
[MAXHOSTNAMELEN
+1];
258 (void) sprintf(pkent
, "%s:%s", public, secret
);
261 /* check that we're on the master server */
262 (void) yp_get_default_domain(&domain
);
263 if (yp_master(domain
, PKMAP
, &master
) != 0) {
264 (void) fprintf(stderr
,
265 "%s: cannot find master of NIS publickey database\n",
269 if (gethostname(hostname
, MAXHOSTNAMELEN
) < 0) {
270 (void) fprintf(stderr
,
271 "%s: cannot find my own host name\n",
275 if (strcmp(master
, hostname
) != 0) {
276 (void) fprintf(stderr
,
277 "%s: can only be used on NIS master machine '%s'\n",
278 program_name
, master
);
282 if (chdir(YPDBPATH
) < 0) {
283 (void) fprintf(stderr
, "%s: cannot chdir to %s",
284 program_name
, YPDBPATH
);
286 (void) fprintf(stdout
,
287 "Please wait for the database to get updated ...\n");
288 return (mapupdate(name
, PKMAP
, YPOP_STORE
, pkent
));
290 return (localupdate(name
, PKFILE
, YPOP_STORE
, pkent
));
292 return (ldap_update("dh192-0", name
, public, secret
, pw
));
302 (void) fprintf(stderr
,
303 "usage:\t%s -u username [-s ldap | nis | files]\n",
305 (void) fprintf(stderr
,
306 "\t%s -h hostname [-s ldap | nis | files]\n",
312 * The parameters passed into the routine get_password and the
313 * return values are as follows:
314 * If the -h flag was specified on the command line:
315 * (a) username is null
316 * (b) target_host is non-null
318 * (d) the login password of root on target_host is returned
320 * If the -u flag was specified on the command line:
321 * (a) username is non-null
322 * (b) target_host is null in all cases except when username is root;
323 * in that case target_host is set to the local host
324 * (c) uid is set to the username's uid
325 * (d) the login password of the user <username> is returned
328 get_password(uid
, target_host
, username
)
333 static char password
[MAXPASSWD
+1];
334 char prompt
[MAXPASSWD
+MAXHOSTNAMELEN
+64];
335 char *encrypted_password
,
336 *login_password
= NULL
,
341 if ((username
!= 0) ||
342 (target_host
!= 0) && (local_host(target_host
))) {
345 * "-u username" or "-h localhost" was specified on the
352 (void) fprintf(stderr
,
353 "%s: unable to locate password record for uid %d\n",
357 spw
= getspnam(pw
->pw_name
);
359 login_password
= spw
->sp_pwdp
;
361 if (! login_password
|| (strlen(login_password
) == 0)) {
362 (void) fprintf(stderr
,
363 "%s: unable to locate shadow password record for %s\n",
364 program_name
, pw
->pw_name
);
369 (void) sprintf(prompt
, "Enter local root login password:");
371 (void) sprintf(prompt
, "Enter %s's login password:",
374 pass
= getpassphrase(prompt
);
375 if (pass
&& strlen(pass
) == 0) {
376 (void) fprintf(stderr
, "%s: Invalid password.\n",
380 strcpy(password
, pass
);
381 encrypted_password
= crypt(password
, login_password
);
383 /* Verify that password supplied matches login password */
384 if (strcmp(encrypted_password
, login_password
) != 0) {
386 * Give another chance for typo
388 pass
= getpassphrase("Please retype password:");
389 if (pass
&& strlen(pass
) == 0) {
390 (void) fprintf(stderr
, "%s: Invalid password.\n",
394 strcpy(password
, pass
);
395 encrypted_password
= crypt(password
, login_password
);
396 if (strcmp(encrypted_password
, login_password
) != 0) {
397 (void) fprintf(stderr
,
398 "%s: ERROR, invalid password.\n",
405 * "-h remotehost" was specified on the command line
407 * Since we cannot verify the root password of the remote
408 * host we have to trust what the user inputs. We can,
409 * however, reduce the possibility of an error by prompting
410 * the user to enter the target host's password twice and
411 * comparing those two. We can also authenticate the
412 * user to be root by checking the real uid.
416 (void) fprintf(stderr
, "Must be superuser to run %s\n",
421 (void) sprintf(prompt
,
422 "Enter %s's root login password:",
424 pass
= getpassphrase(prompt
);
426 (void) fprintf(stderr
,
427 "%s: getpass failed.\n",
432 (void) fprintf(stderr
,
433 "%s: Invalid root password.\n",
437 strcpy(password
, pass
);
440 * Now re-enter the password and compare it to the
443 (void) sprintf(prompt
,
444 "Please confirm %s's root login password:",
446 pass
= getpassphrase(prompt
);
448 (void) fprintf(stderr
,
449 "%s: getpass failed.\n",
454 (void) fprintf(stderr
,
455 "%s: Invalid root password.\n",
459 if (strcmp(pass
, password
) != 0) {
460 (void) fprintf(stderr
,
461 "%s: Password Incorrect.\n",