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