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 1997-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * gsscred utility
31 * Manages mapping between a security principal name and unix uid
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <pwd.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <gssapi/gssapi_ext.h>
40 #include "gsscred.h"
41
42 #define MAX_STR_LEN 1024
43
44
45 /*
46 * Internal Functions
47 */
48 static void usage(void);
49 static void addUser(const char *name, const char *oid, const char *userUid,
50 const char *userComment, const char *userMech);
51 static int file_listUsers(const gss_OID mechOid, const char *userUid,
52 char **errDetails);
53 static int listUsers(const char *name, const char *nameTypeOid,
54 const char *uid, const char *mechOid);
55 static int file_removeUsers(const gss_OID mechOid, const char *userUid,
56 char **errDetails);
57 static int removeUsers(const char *name, const char *nameTypeOid,
58 const char *uid, const char *mechOid);
59
60 /*
61 * Global variables
62 */
63 static int tableSource;
64 static char *PROG_NAME = NULL;
65
66 int
main(int argc,char * args[])67 main(int argc, char *args[])
68 {
69 char *userName = NULL, *nameTypeOID = NULL,
70 *uid = NULL, *comment = NULL, *mech = NULL,
71 operation = '0';
72 int c, errflag = 0;
73 extern char *optarg;
74
75 PROG_NAME = *args;
76
77 /* set locale and domain for internationalization */
78 setlocale(LC_ALL, "");
79 textdomain(TEXT_DOMAIN);
80
81 if (argc < 2)
82 usage();
83
84 /* Process the input arguments */
85 while ((c = getopt(argc, args, "arln:o:u:m:c:")) != EOF) {
86
87 switch (c) {
88 case 'n':
89 userName = optarg;
90 break;
91
92 case 'o':
93 nameTypeOID = optarg;
94 break;
95
96 case 'u':
97 uid = optarg;
98 break;
99
100 case 'm':
101 mech = optarg;
102 break;
103
104 case 'c':
105 comment = optarg;
106 break;
107
108 case 'a':
109 case 'r':
110 case 'l':
111 operation = c;
112 errflag++;
113 if (errflag > 1)
114 usage();
115 break;
116
117 default:
118 usage();
119 }
120 }
121
122 /* determine which back-end to use as the gsscred store */
123 tableSource = gsscred_read_config_file();
124
125 /* perform the requested operation */
126 switch (operation) {
127 case 'a':
128 addUser(userName, nameTypeOID, uid, comment, mech);
129 break;
130
131 case 'r':
132 removeUsers(userName, nameTypeOID, uid, mech);
133 break;
134
135 case 'l':
136 listUsers(userName, nameTypeOID, uid, mech);
137 break;
138
139 default:
140 usage();
141 }
142 fprintf(stdout, "\n");
143 return (0);
144 } /* main */
145
146 /*
147 * Handles the addition of users to the gsscred table.
148 */
149 static void
addUser(const char * name,const char * nameOidStr,const char * userUid,const char * userComment,const char * mechOidStr)150 addUser(const char *name, const char *nameOidStr,
151 const char *userUid, const char *userComment,
152 const char *mechOidStr)
153 {
154 gss_OID mechOid;
155 gss_buffer_desc fullName = GSS_C_EMPTY_BUFFER,
156 hexBufDesc = GSS_C_EMPTY_BUFFER,
157 hexMechOid = GSS_C_EMPTY_BUFFER;
158 char comment[MAX_STR_LEN+1], hexBuf[MAX_STR_LEN+MAX_STR_LEN+1],
159 hexMechOidBuf[MAX_STR_LEN+1], *commentPtr = NULL,
160 *errDetail = NULL, uidStr[256], *uidPtr;
161 struct passwd *aUser;
162 OM_uint32 minor;
163 int count = 0, retCode;
164
165 hexMechOid.length = MAX_STR_LEN;
166 hexMechOid.value = (void*)hexMechOidBuf;
167
168 /* addition of users can only be performed by super users */
169 if (getuid()) {
170 fprintf(stderr,
171 gettext("\nUser addition requires"
172 " root privileges."));
173 return;
174 }
175
176 /* the mechanism OID is required */
177 if (mechOidStr == NULL) {
178 fprintf(stderr, gettext("\nUnspecified mechanism."));
179 usage();
180 }
181
182 /* Convert from string mechanism Oid to ASN.1 oid and then hex */
183 if (__gss_mech_to_oid(mechOidStr, &mechOid) != GSS_S_COMPLETE) {
184 fprintf(stderr,
185 gettext("\nInvalid mechanism specified [%s]."),
186 mechOidStr);
187 return;
188 }
189
190 hexBufDesc.length = mechOid->length;
191 hexBufDesc.value = mechOid->elements;
192
193 if (!gsscred_AsHex(&hexBufDesc, &hexMechOid)) {
194 fprintf(stderr,
195 gettext("\nInternal error. "
196 "Conversion to hex failed."));
197 return;
198 }
199
200 /*
201 * if the name is specified, then do single addition.
202 * Might have to look up the uid.
203 */
204 if (name != NULL) {
205 hexBufDesc.length = sizeof (hexBuf);
206 hexBufDesc.value = hexBuf;
207
208 /* build the name as needed */
209 if (!gsscred_MakeName(mechOid, name, nameOidStr, &fullName)) {
210 fprintf(stderr,
211 gettext("\nError adding user [%s]."), name);
212 return;
213 }
214
215 /* convert it to hex */
216 if (!gsscred_AsHex(&fullName, &hexBufDesc)) {
217 gss_release_buffer(&minor, &fullName);
218 fprintf(stderr,
219 gettext("\nInternal error. "
220 "Conversion to hex failed."));
221 return;
222 }
223
224 /* might require the lookup of the uid if one not specified */
225 if (userUid == NULL) {
226
227 if ((aUser = getpwnam(name)) == NULL) {
228 fprintf(stderr,
229 gettext("\nUnable to obtain password"
230 " information for [%s]."),
231 name);
232 gss_release_buffer(&minor, &fullName);
233 return;
234 }
235 sprintf(uidStr, "%ld", aUser->pw_uid);
236 uidPtr = uidStr;
237 }
238 else
239 uidPtr = (char *)userUid;
240
241 if (userComment == NULL) {
242 sprintf(comment, "%s, %s", name, mechOidStr);
243 commentPtr = comment;
244 } else
245 commentPtr = (char *)userComment;
246
247 if (tableSource == GSSCRED_FLAT_FILE)
248 retCode = file_addGssCredEntry(&hexBufDesc,
249 uidPtr, commentPtr, &errDetail);
250 else
251 /* other backends (ldap, dss) coming soon */
252 retCode = 0;
253
254 if (!retCode) {
255 fprintf(stderr, gettext("\nError adding user [%s]."),
256 commentPtr);
257
258 if (errDetail) {
259 fprintf(stderr, "\n%s\n", errDetail);
260 free(errDetail);
261 errDetail = NULL;
262 }
263 }
264
265 gss_release_buffer(&minor, &fullName);
266 return;
267 }
268
269 /*
270 * since no name specified, then we will load everyone from
271 * password table. This means that -u and -o options are invalid.
272 * We just ignore it, but we could flag it as error.
273 */
274 setpwent();
275
276 while ((aUser = getpwent()) != NULL) {
277 hexBufDesc.length = sizeof (hexBuf);
278 hexBufDesc.value = hexBuf;
279
280 if (!gsscred_MakeName(mechOid, aUser->pw_name,
281 nameOidStr, &fullName)) {
282 fprintf(stderr,
283 gettext("\nError adding user [%s]."),
284 aUser->pw_name);
285 continue;
286 }
287
288 if (!gsscred_AsHex(&fullName, &hexBufDesc)) {
289 gss_release_buffer(&minor, &fullName);
290 fprintf(stderr,
291 gettext("\nInternal error. "
292 "Conversion to hex failed."));
293 continue;
294 }
295
296 sprintf(uidStr, "%ld", aUser->pw_uid);
297 sprintf(comment, "%s, %s", aUser->pw_name, mechOidStr);
298 if (tableSource == GSSCRED_FLAT_FILE)
299 retCode = file_addGssCredEntry(&hexBufDesc,
300 uidStr, comment, &errDetail);
301 else
302 retCode = 0;
303
304 if (!retCode) {
305 fprintf(stderr,
306 gettext("\nError adding user [%s]."),
307 comment);
308
309 if (errDetail) {
310 fprintf(stderr, "\n%s\n", errDetail);
311 free(errDetail);
312 errDetail = NULL;
313 }
314 } else {
315 count++;
316 if ((count % 50) == 0)
317 fprintf(stdout,
318 gettext("\n[%d] users added..."),
319 count);
320 }
321 gss_release_buffer(&minor, &fullName);
322 }
323 endpwent();
324 } /* addUser */
325
326
327 /*
328 * Handles the searching of the gsscred table.
329 */
listUsers(const char * name,const char * nameOidStr,const char * uidStr,const char * mechOidStr)330 static int listUsers(const char *name, const char *nameOidStr,
331 const char *uidStr, const char *mechOidStr)
332 {
333 GssCredEntry *entryPtr, *entryTmpPtr;
334 char hexMech[256],
335 hexName[(MAX_STR_LEN *2) + 1];
336 gss_OID anOid = NULL, userMechOid = NULL;
337 gss_OID_set mechSet = NULL;
338 gss_buffer_desc inBufDesc = GSS_C_EMPTY_BUFFER,
339 outBufDesc = GSS_C_EMPTY_BUFFER,
340 searchName = GSS_C_EMPTY_BUFFER;
341 int status = 1, numOfMechs, i;
342 OM_uint32 minor;
343 char *errDetails = NULL;
344
345 /* Do we need to convert the mechanism oid? */
346 if (mechOidStr != NULL) {
347
348 if (__gss_mech_to_oid(mechOidStr, &userMechOid) !=
349 GSS_S_COMPLETE) {
350 fprintf(stderr,
351 gettext("\nInvalid mechanism specified [%s]."),
352 mechOidStr);
353 return (0);
354 }
355 inBufDesc.length = userMechOid->length;
356 inBufDesc.value = userMechOid->elements;
357 outBufDesc.length = sizeof (hexMech);
358 outBufDesc.value = hexMech;
359
360 if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) {
361 fprintf(stderr,
362 gettext("\nInternal error. "
363 "Conversion to hex failed."));
364 status = 0;
365 goto cleanup;
366 }
367
368 } /* mechOidStr != NULL */
369
370 /* are we retrieving everyone ? or searching by mech ? */
371 if ((name == NULL && uidStr == NULL && mechOidStr == NULL) ||
372 (name == NULL && uidStr == NULL)) {
373
374 if (tableSource == GSSCRED_FLAT_FILE) {
375 file_listUsers(userMechOid, NULL, &errDetails);
376
377 if (errDetails) {
378 fprintf(stderr,
379 gettext("\nError searching gsscred"
380 " table [%s]."),
381 errDetails);
382 free(errDetails);
383 errDetails = NULL;
384 return (0);
385 }
386 return (1);
387 }
388
389 }
390
391 /* Are we searching by uid or uid and mech? */
392 if (name == NULL && uidStr != NULL) {
393
394 if (tableSource == GSSCRED_FLAT_FILE)
395 file_listUsers(userMechOid, uidStr, &errDetails);
396 else {
397 entryPtr = NULL;
398 while (entryPtr != NULL) {
399 fprintf(stdout, "\n%s\t%d\t%s",
400 entryPtr->principal_name,
401 entryPtr->unix_uid, entryPtr->comment);
402 free(entryPtr->principal_name);
403 free(entryPtr->comment);
404 entryTmpPtr = entryPtr->next;
405 free(entryPtr);
406 entryPtr = entryTmpPtr;
407 }
408 }
409
410 /* check for any errors */
411 if (errDetails) {
412 fprintf(stderr,
413 gettext("\nError searching gsscred table "
414 "[%s]."),
415 errDetails);
416 free(errDetails);
417 errDetails = NULL;
418 status = 0;
419 }
420
421 goto cleanup;
422 }
423
424 /*
425 * We are searching by name;
426 * how many mechs must we check?
427 */
428 if (mechOidStr == NULL) {
429
430 if (gss_indicate_mechs(&minor, &mechSet) != GSS_S_COMPLETE) {
431 fprintf(stderr,
432 gettext("\nInternal error. "
433 "GSS-API call failed."));
434 return (0);
435 }
436 numOfMechs = mechSet->count;
437 }
438 else
439 numOfMechs = 1;
440
441 /* now look through all the mechs searching */
442 for (i = 0; i < numOfMechs; i++) {
443
444 if (mechOidStr == NULL) {
445 anOid = &mechSet->elements[i];
446 inBufDesc.length = anOid->length;
447 inBufDesc.value = anOid->elements;
448 outBufDesc.length = sizeof (hexMech);
449 outBufDesc.value = hexMech;
450
451 if (!gsscred_AsHex(&inBufDesc, &outBufDesc))
452 continue;
453 } else
454 anOid = userMechOid;
455
456 /* create a gss name */
457 if (!gsscred_MakeName(anOid, name, nameOidStr, &outBufDesc))
458 continue;
459
460 /* now convert it to hex, and find it */
461 searchName.value = hexName;
462 searchName.length = sizeof (hexName);
463 status = gsscred_AsHex(&outBufDesc, &searchName);
464 free(outBufDesc.value);
465
466 if (!status)
467 continue;
468
469 if (tableSource == GSSCRED_FLAT_FILE)
470 file_getGssCredEntry(&searchName, uidStr, &errDetails);
471 else {
472 entryPtr = NULL; /* other backends coming soon */
473 while (entryPtr != NULL) {
474 fprintf(stdout, "\n%s\t%d\t%s",
475 entryPtr->principal_name,
476 entryPtr->unix_uid, entryPtr->comment);
477 free(entryPtr->principal_name);
478 free(entryPtr->comment);
479 entryTmpPtr = entryPtr->next;
480 free(entryPtr);
481 entryPtr = entryTmpPtr;
482 }
483 }
484
485 /* any errors to display */
486 if (errDetails) {
487 fprintf(stderr,
488 gettext("\nError searching gsscred table "
489 "[%s]."),
490 errDetails);
491 free(errDetails);
492 errDetails = NULL;
493 status = 0;
494 }
495 } /* for */
496
497 cleanup:
498 if (mechSet != NULL)
499 gss_release_oid_set(&minor, &mechSet);
500
501 return (status);
502 } /* listUsers */
503
504 /*
505 * Performs additional handling while searching for users
506 * stored in the flat file table.
507 */
508 int
file_listUsers(const gss_OID mechOid,const char * unixUid,char ** errDetails)509 file_listUsers(const gss_OID mechOid, const char *unixUid,
510 char **errDetails)
511 {
512 gss_buffer_desc mechBufDesc = GSS_C_EMPTY_BUFFER,
513 mechHexBufDesc = GSS_C_EMPTY_BUFFER;
514 char mechBuf[128], mechHexBuf[256];
515
516 if (mechOid != NULL) {
517 /* must make the name header whic contains mech oid */
518 mechBufDesc.value = (void *) mechBuf;
519 mechBufDesc.length = sizeof (mechBuf);
520 mechHexBufDesc.value = (void*) mechHexBuf;
521 mechHexBufDesc.length = sizeof (mechHexBuf);
522
523 if ((!gsscred_MakeNameHeader(mechOid, &mechBufDesc)) ||
524 (!gsscred_AsHex(&mechBufDesc, &mechHexBufDesc))) {
525 (*errDetails) = strdup(
526 gettext("\nInternal error. "
527 " Conversion to hex failed."));
528 return (0);
529 }
530
531 return (file_getGssCredEntry(&mechHexBufDesc,
532 unixUid, errDetails));
533 }
534
535 return (file_getGssCredEntry(NULL, unixUid, errDetails));
536 } /* file_listUsers */
537
538
539 /*
540 * Handles the deletion of users.
541 */
removeUsers(const char * name,const char * nameOidStr,const char * uidStr,const char * mechOidStr)542 static int removeUsers(const char *name, const char *nameOidStr,
543 const char *uidStr, const char *mechOidStr)
544 {
545 char hexMech[256],
546 hexName[(MAX_STR_LEN *2) + 1],
547 *errDetails = NULL;
548 gss_OID anOid = NULL, userMechOid = NULL;
549 gss_OID_set mechSet = NULL;
550 gss_buffer_desc inBufDesc = GSS_C_EMPTY_BUFFER,
551 outBufDesc = GSS_C_EMPTY_BUFFER,
552 searchName = GSS_C_EMPTY_BUFFER;
553 int status = 0, numOfMechs, i;
554 OM_uint32 minor;
555
556
557 /* user deletion can only be performed by super user */
558 if (getuid()) {
559
560 fprintf(stderr,
561 gettext("\nUser deletion requires"
562 " root privileges."));
563 return (0);
564 }
565
566 /* do we need to convert the mechanism oid? */
567 if (mechOidStr != NULL) {
568 if (__gss_mech_to_oid(mechOidStr, &userMechOid) !=
569 GSS_S_COMPLETE) {
570 fprintf(stderr,
571 gettext("\nInvalid mechanism specified [%s]."),
572 mechOidStr);
573 return (0);
574 }
575
576 inBufDesc.length = userMechOid->length;
577 inBufDesc.value = userMechOid->elements;
578 outBufDesc.length = sizeof (hexMech);
579 outBufDesc.value = hexMech;
580
581 if (!gsscred_AsHex(&inBufDesc, &outBufDesc)) {
582 fprintf(stderr,
583 gettext("\nInternal error."
584 " Conversion to hex failed."));
585 status = 0;
586 goto cleanup;
587 }
588
589 } /* mechOidStr != NULL */
590
591 /* are we deleting the entire table or an entire mech ? */
592 if (name == NULL && uidStr == NULL) {
593
594 if (tableSource == GSSCRED_FLAT_FILE)
595 status = file_removeUsers(userMechOid,
596 NULL, &errDetails);
597 else
598 status = 0;
599
600 /* display any errors */
601 if (errDetails) {
602 fprintf(stderr,
603 gettext("\nError deleting gsscred entry "
604 "[%s]."),
605 errDetails);
606 free(errDetails);
607 errDetails = NULL;
608 }
609 goto cleanup;
610 }
611
612 /* are we deleting by uid or uid and mech? */
613 if (name == NULL && uidStr != NULL) {
614
615 if (tableSource == GSSCRED_FLAT_FILE)
616 status = file_removeUsers(userMechOid, uidStr,
617 &errDetails);
618 else
619 status = 0;
620
621 /* check for any errors */
622 if (errDetails) {
623 fprintf(stderr,
624 gettext("\nError deleting gsscred entry "
625 "[%s]."),
626 errDetails);
627 free(errDetails);
628 errDetails = NULL;
629 }
630 goto cleanup;
631 }
632
633 /*
634 * We are deleting by name;
635 * how many mechs must we check?
636 */
637 if (mechOidStr == NULL) {
638
639 if (gss_indicate_mechs(&minor, &mechSet) != GSS_S_COMPLETE) {
640 fprintf(stderr,
641 gettext("\nInternal error. "
642 "GSS-API call failed."));
643 status = 0;
644 goto cleanup;
645 }
646 numOfMechs = mechSet->count;
647 }
648 else
649 numOfMechs = 1;
650
651 /* now look through all the mechs, deleting */
652 for (i = 0; i < numOfMechs; i++) {
653
654 if (mechOidStr == NULL) {
655 anOid = &mechSet->elements[i];
656 inBufDesc.length = anOid->length;
657 inBufDesc.value = anOid->elements;
658 outBufDesc.length = sizeof (hexMech);
659 outBufDesc.value = hexMech;
660 if (!gsscred_AsHex(&inBufDesc, &outBufDesc))
661 continue;
662 } else
663 anOid = userMechOid;
664
665 /* create a gss name */
666 if (!gsscred_MakeName(anOid, name, nameOidStr, &outBufDesc))
667 continue;
668
669 /* now convert it to hex, and delete it */
670 searchName.value = hexName;
671 searchName.length = sizeof (hexName);
672 status = gsscred_AsHex(&outBufDesc, &searchName);
673 free(outBufDesc.value);
674
675 if (!status)
676 continue;
677
678 if (tableSource == GSSCRED_FLAT_FILE)
679 status = file_deleteGssCredEntry(&searchName,
680 uidStr, &errDetails);
681 else
682 status = 0;
683
684 /* check for any errors */
685 if (errDetails) {
686 fprintf(stderr,
687 gettext("\nError deleting gsscred entry"
688 " [%s]."),
689 errDetails);
690 free(errDetails);
691 errDetails = NULL;
692 }
693 } /* for */
694
695 cleanup:
696 if (mechSet != NULL)
697 gss_release_oid_set(&minor, &mechSet);
698
699 return (status);
700 } /* removeUsers */
701
702
703 /*
704 * Performs additional handling while deleting users
705 * stored in the flat file table.
706 */
file_removeUsers(const gss_OID mechOid,const char * unixUid,char ** errDetails)707 int file_removeUsers(const gss_OID mechOid, const char *unixUid,
708 char **errDetails)
709 {
710 gss_buffer_desc mechBufDesc = GSS_C_EMPTY_BUFFER,
711 mechHexBufDesc = GSS_C_EMPTY_BUFFER;
712 char mechBuf[128], mechHexBuf[256];
713
714 if (mechOid != NULL) {
715 /*
716 * need to create the buffer header which contains
717 * the mechanism oid.
718 */
719 mechBufDesc.value = (void*) mechBuf;
720 mechBufDesc.length = sizeof (mechBuf);
721 mechHexBufDesc.value = (void *) mechHexBuf;
722 mechHexBufDesc.length = sizeof (mechHexBuf);
723
724 if ((!gsscred_MakeNameHeader(mechOid, &mechBufDesc)) ||
725 (!gsscred_AsHex(&mechBufDesc, &mechHexBufDesc))) {
726 (*errDetails) = strdup(
727 gettext("\nInternal error."
728 " Conversion to hex failed."));
729 return (0);
730 }
731
732 return (file_deleteGssCredEntry(&mechHexBufDesc, unixUid,
733 errDetails));
734 }
735
736 return (file_deleteGssCredEntry(NULL, unixUid, errDetails));
737 } /* file_removeUsers */
738
739
740 /*
741 * Prints the usage string, and terminates.
742 */
usage(void)743 static void usage(void)
744 {
745
746 fprintf(stderr,
747 gettext("\nUsage:\t %s [-n user [-o oid] [-u uid]]"
748 " [-c comment] -m mech -a"
749 "\n\t %s [-n user [-o oid]] [-u uid] [-m mech] -r"
750 "\n\t %s [-n user [-o oid]] [-u uid] [-m mech] -l\n"),
751 PROG_NAME, PROG_NAME, PROG_NAME);
752 exit(1);
753 } /* usage */
754