1*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
2*0Sstevel@tonic-gate
3*0Sstevel@tonic-gate /****************************************************************************
4*0Sstevel@tonic-gate
5*0Sstevel@tonic-gate Copyright (c) 1999,2000 WU-FTPD Development Group.
6*0Sstevel@tonic-gate All rights reserved.
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gate Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
9*0Sstevel@tonic-gate The Regents of the University of California. Portions Copyright (c)
10*0Sstevel@tonic-gate 1993, 1994 Washington University in Saint Louis. Portions Copyright
11*0Sstevel@tonic-gate (c) 1996, 1998 Berkeley Software Design, Inc. Portions Copyright (c)
12*0Sstevel@tonic-gate 1998 Sendmail, Inc. Portions Copyright (c) 1983, 1995, 1996, 1997 Eric
13*0Sstevel@tonic-gate P. Allman. Portions Copyright (c) 1989 Massachusetts Institute of
14*0Sstevel@tonic-gate Technology. Portions Copyright (c) 1997 by Stan Barber. Portions
15*0Sstevel@tonic-gate Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997 Free Software
16*0Sstevel@tonic-gate Foundation, Inc. Portions Copyright (c) 1997 by Kent Landfield.
17*0Sstevel@tonic-gate
18*0Sstevel@tonic-gate Use and distribution of this software and its source code are governed
19*0Sstevel@tonic-gate by the terms and conditions of the WU-FTPD Software License ("LICENSE").
20*0Sstevel@tonic-gate
21*0Sstevel@tonic-gate $Id: privatepw.c,v 1.10 2000/07/01 18:43:59 wuftpd Exp $
22*0Sstevel@tonic-gate
23*0Sstevel@tonic-gate ****************************************************************************/
24*0Sstevel@tonic-gate /*
25*0Sstevel@tonic-gate Subsystem: WU-FTPD FTP Server
26*0Sstevel@tonic-gate Purpose: Change WU-FTPD Guest Passwords
27*0Sstevel@tonic-gate File Name: privatepw.c
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate usage: privatepw [-c] [-f passwordfile] [-g group] accessgroup
30*0Sstevel@tonic-gate privatepw [-d] [-f passwordfile] accessgroup
31*0Sstevel@tonic-gate privatepw [-l] [-f passwordfile]
32*0Sstevel@tonic-gate -c: creates a new file.
33*0Sstevel@tonic-gate -d: deletes specified accessgroup.
34*0Sstevel@tonic-gate -l: list contents of ftpgroups file.
35*0Sstevel@tonic-gate -f ftpgroups: updates the specified file.
36*0Sstevel@tonic-gate -g group: set real group to the specified group.
37*0Sstevel@tonic-gate
38*0Sstevel@tonic-gate This software was initially written by Kent Landfield (kent@landfield.com)
39*0Sstevel@tonic-gate */
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate #include <sys/types.h>
42*0Sstevel@tonic-gate #include <sys/signal.h>
43*0Sstevel@tonic-gate #include <sys/stat.h>
44*0Sstevel@tonic-gate #include <string.h>
45*0Sstevel@tonic-gate #include <stdio.h>
46*0Sstevel@tonic-gate #include <stdlib.h>
47*0Sstevel@tonic-gate #include <time.h>
48*0Sstevel@tonic-gate #include <grp.h>
49*0Sstevel@tonic-gate #include <unistd.h>
50*0Sstevel@tonic-gate #include "config.h"
51*0Sstevel@tonic-gate #include "pathnames.h"
52*0Sstevel@tonic-gate
53*0Sstevel@tonic-gate #define BUFLEN 256
54*0Sstevel@tonic-gate #define GROUPLEN 8
55*0Sstevel@tonic-gate
56*0Sstevel@tonic-gate char *tmp;
57*0Sstevel@tonic-gate char line[BUFLEN];
58*0Sstevel@tonic-gate FILE *fp;
59*0Sstevel@tonic-gate int verbose = 0;
60*0Sstevel@tonic-gate
61*0Sstevel@tonic-gate static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
62*0Sstevel@tonic-gate "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
63*0Sstevel@tonic-gate
64*0Sstevel@tonic-gate void print_copyright(void);
65*0Sstevel@tonic-gate
usage(void)66*0Sstevel@tonic-gate static void usage(void)
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate fprintf(stderr, "usage: privatepw [-c] [-f ftpgroups] [-g group] accessgroup\n");
69*0Sstevel@tonic-gate fprintf(stderr, " privatepw [-d] [-f ftpgroups] accessgroup\n");
70*0Sstevel@tonic-gate fprintf(stderr, " privatepw [-l] [-f ftpgroups]\n");
71*0Sstevel@tonic-gate fprintf(stderr, "\t\t-c: creates a new file.\n");
72*0Sstevel@tonic-gate fprintf(stderr, "\t\t-d: deletes specified accessgroup.\n");
73*0Sstevel@tonic-gate fprintf(stderr, "\t\t-l: list contents of ftpgroups file.\n");
74*0Sstevel@tonic-gate fprintf(stderr, "\t\t-f ftpgroups: updates the specified file.\n");
75*0Sstevel@tonic-gate fprintf(stderr, "\t\t-g group: set real group to the specified group.\n");
76*0Sstevel@tonic-gate exit(1);
77*0Sstevel@tonic-gate }
78*0Sstevel@tonic-gate
to64(register char * s,register long v,register int n)79*0Sstevel@tonic-gate static void to64(register char *s, register long v, register int n)
80*0Sstevel@tonic-gate {
81*0Sstevel@tonic-gate while (--n >= 0) {
82*0Sstevel@tonic-gate *s++ = itoa64[v & 0x3f];
83*0Sstevel@tonic-gate v >>= 6;
84*0Sstevel@tonic-gate }
85*0Sstevel@tonic-gate }
86*0Sstevel@tonic-gate
terminate(void)87*0Sstevel@tonic-gate static void terminate(void)
88*0Sstevel@tonic-gate {
89*0Sstevel@tonic-gate if (tmp)
90*0Sstevel@tonic-gate unlink(tmp);
91*0Sstevel@tonic-gate exit(1);
92*0Sstevel@tonic-gate }
93*0Sstevel@tonic-gate
catchintr(void)94*0Sstevel@tonic-gate static void catchintr(void)
95*0Sstevel@tonic-gate {
96*0Sstevel@tonic-gate fprintf(stderr, "Interrupted.\n");
97*0Sstevel@tonic-gate terminate();
98*0Sstevel@tonic-gate }
99*0Sstevel@tonic-gate
savit(char * s)100*0Sstevel@tonic-gate static char *savit(char *s)
101*0Sstevel@tonic-gate {
102*0Sstevel@tonic-gate char *d;
103*0Sstevel@tonic-gate
104*0Sstevel@tonic-gate if ((d = (char *) malloc(strlen(s) + 1)) == NULL) {
105*0Sstevel@tonic-gate fprintf(stderr, "Whoa... Malloc failed.\n");
106*0Sstevel@tonic-gate terminate();
107*0Sstevel@tonic-gate }
108*0Sstevel@tonic-gate strcpy(d, s);
109*0Sstevel@tonic-gate return (d);
110*0Sstevel@tonic-gate }
111*0Sstevel@tonic-gate
confirmed(char * accessgroup)112*0Sstevel@tonic-gate static int confirmed(char *accessgroup)
113*0Sstevel@tonic-gate {
114*0Sstevel@tonic-gate register int ch;
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate printf("Delete %s: Are your sure ? (y/n) ", accessgroup);
117*0Sstevel@tonic-gate ch = getc(stdin);
118*0Sstevel@tonic-gate if (ch == 'y')
119*0Sstevel@tonic-gate return (1);
120*0Sstevel@tonic-gate return (0);
121*0Sstevel@tonic-gate }
122*0Sstevel@tonic-gate
getgroup(char * msg)123*0Sstevel@tonic-gate static char *getgroup(char *msg)
124*0Sstevel@tonic-gate {
125*0Sstevel@tonic-gate register int ch;
126*0Sstevel@tonic-gate register char *p;
127*0Sstevel@tonic-gate static char buf[GROUPLEN + 1];
128*0Sstevel@tonic-gate
129*0Sstevel@tonic-gate fputs(msg, stderr);
130*0Sstevel@tonic-gate rewind(stderr); /* implied flush */
131*0Sstevel@tonic-gate for (p = buf; (ch = getc(stdin)) != EOF && ch != '\n';)
132*0Sstevel@tonic-gate if (p < buf + GROUPLEN)
133*0Sstevel@tonic-gate *p++ = ch;
134*0Sstevel@tonic-gate *p = '\0';
135*0Sstevel@tonic-gate
136*0Sstevel@tonic-gate if (getgrnam(buf) == NULL) {
137*0Sstevel@tonic-gate fprintf(stderr, "Invalid group \'%s\' specified\n", buf);
138*0Sstevel@tonic-gate terminate();
139*0Sstevel@tonic-gate }
140*0Sstevel@tonic-gate return (buf);
141*0Sstevel@tonic-gate }
142*0Sstevel@tonic-gate
addrecord(char * accessgroup,char * sysgroup,char * msg,FILE * f)143*0Sstevel@tonic-gate static void addrecord(char *accessgroup, char *sysgroup, char *msg, FILE *f)
144*0Sstevel@tonic-gate {
145*0Sstevel@tonic-gate char *pw, *cpw, salt[3];
146*0Sstevel@tonic-gate #ifndef NO_CRYPT_PROTO
147*0Sstevel@tonic-gate extern char *crypt(const char *, const char *);
148*0Sstevel@tonic-gate #endif
149*0Sstevel@tonic-gate char *getpass(const char *prompt);
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate printf("%s %s\n", msg, accessgroup);
152*0Sstevel@tonic-gate
153*0Sstevel@tonic-gate if (sysgroup[0] == '\0')
154*0Sstevel@tonic-gate strcpy(sysgroup, getgroup("Real System Group to use: "));
155*0Sstevel@tonic-gate
156*0Sstevel@tonic-gate pw = savit((char *) getpass("New password: "));
157*0Sstevel@tonic-gate if (strcmp(pw, (char *) getpass("Re-type new password: "))) {
158*0Sstevel@tonic-gate fprintf(stderr, "They don't match, sorry.\n");
159*0Sstevel@tonic-gate if (tmp)
160*0Sstevel@tonic-gate unlink(tmp);
161*0Sstevel@tonic-gate exit(1);
162*0Sstevel@tonic-gate }
163*0Sstevel@tonic-gate
164*0Sstevel@tonic-gate srand((int) time((time_t *) NULL));
165*0Sstevel@tonic-gate to64(&salt[0], rand(), 2);
166*0Sstevel@tonic-gate cpw = crypt(pw, salt);
167*0Sstevel@tonic-gate free(pw);
168*0Sstevel@tonic-gate fprintf(f, "%s:%s:%s\n", accessgroup, cpw, sysgroup);
169*0Sstevel@tonic-gate }
170*0Sstevel@tonic-gate
list_privatefile(char * privatefile)171*0Sstevel@tonic-gate static void list_privatefile(char *privatefile)
172*0Sstevel@tonic-gate {
173*0Sstevel@tonic-gate if (verbose)
174*0Sstevel@tonic-gate fprintf(stderr, "Private File: %s file.\n", privatefile);
175*0Sstevel@tonic-gate
176*0Sstevel@tonic-gate if ((fp = fopen(privatefile, "r")) == NULL) {
177*0Sstevel@tonic-gate fprintf(stderr, "Could not open %s file.\n", privatefile);
178*0Sstevel@tonic-gate exit(1);
179*0Sstevel@tonic-gate }
180*0Sstevel@tonic-gate
181*0Sstevel@tonic-gate printf("\nWU-FTPD Private file: %s\n", privatefile);
182*0Sstevel@tonic-gate printf("accessgroup : password : system group\n");
183*0Sstevel@tonic-gate printf("-------\n");
184*0Sstevel@tonic-gate
185*0Sstevel@tonic-gate while (fgets(line, BUFLEN, fp) != NULL)
186*0Sstevel@tonic-gate fputs(line, stdout);
187*0Sstevel@tonic-gate printf("-------\n");
188*0Sstevel@tonic-gate }
189*0Sstevel@tonic-gate
main(int argc,char ** argv)190*0Sstevel@tonic-gate int main(int argc, char **argv)
191*0Sstevel@tonic-gate {
192*0Sstevel@tonic-gate extern void (*signal(int sig, void (*disp) (int))) (int);
193*0Sstevel@tonic-gate extern int getopt(int argc, char *const *argv, const char *optstring);
194*0Sstevel@tonic-gate extern char *optarg;
195*0Sstevel@tonic-gate extern int optind;
196*0Sstevel@tonic-gate extern int opterr;
197*0Sstevel@tonic-gate
198*0Sstevel@tonic-gate struct stat stbuf;
199*0Sstevel@tonic-gate
200*0Sstevel@tonic-gate char realgroup[BUFLEN];
201*0Sstevel@tonic-gate char *passwdpath;
202*0Sstevel@tonic-gate char *cp;
203*0Sstevel@tonic-gate
204*0Sstevel@tonic-gate char accessgroup[BUFLEN];
205*0Sstevel@tonic-gate char w[BUFLEN];
206*0Sstevel@tonic-gate char command[BUFLEN];
207*0Sstevel@tonic-gate
208*0Sstevel@tonic-gate int create;
209*0Sstevel@tonic-gate int delete;
210*0Sstevel@tonic-gate int list;
211*0Sstevel@tonic-gate int found;
212*0Sstevel@tonic-gate int lineno;
213*0Sstevel@tonic-gate int c;
214*0Sstevel@tonic-gate
215*0Sstevel@tonic-gate FILE *tfp;
216*0Sstevel@tonic-gate
217*0Sstevel@tonic-gate #ifdef HAVE_MKSTEMP
218*0Sstevel@tonic-gate char tmpname[BUFLEN];
219*0Sstevel@tonic-gate int tfd;
220*0Sstevel@tonic-gate #endif
221*0Sstevel@tonic-gate
222*0Sstevel@tonic-gate opterr = 0;
223*0Sstevel@tonic-gate create = 0;
224*0Sstevel@tonic-gate delete = 0;
225*0Sstevel@tonic-gate list = 0;
226*0Sstevel@tonic-gate
227*0Sstevel@tonic-gate tmp = NULL;
228*0Sstevel@tonic-gate realgroup[0] = '\0';
229*0Sstevel@tonic-gate
230*0Sstevel@tonic-gate passwdpath = _PATH_PRIVATE;
231*0Sstevel@tonic-gate
232*0Sstevel@tonic-gate if (argc == 1)
233*0Sstevel@tonic-gate usage();
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gate while ((c = getopt(argc, argv, "Vvcdf:g:l")) != EOF) {
236*0Sstevel@tonic-gate switch (c) {
237*0Sstevel@tonic-gate case 'd':
238*0Sstevel@tonic-gate delete++;
239*0Sstevel@tonic-gate break;
240*0Sstevel@tonic-gate case 'c':
241*0Sstevel@tonic-gate create++;
242*0Sstevel@tonic-gate break;
243*0Sstevel@tonic-gate case 'f':
244*0Sstevel@tonic-gate passwdpath = optarg;
245*0Sstevel@tonic-gate break;
246*0Sstevel@tonic-gate case 'g':
247*0Sstevel@tonic-gate strcpy(realgroup, optarg);
248*0Sstevel@tonic-gate if (getgrnam(realgroup) == NULL) {
249*0Sstevel@tonic-gate fprintf(stderr, "Invalid group \'%s\' specified\n", realgroup);
250*0Sstevel@tonic-gate return (1);
251*0Sstevel@tonic-gate }
252*0Sstevel@tonic-gate break;
253*0Sstevel@tonic-gate case 'l':
254*0Sstevel@tonic-gate list++;
255*0Sstevel@tonic-gate break;
256*0Sstevel@tonic-gate case 'v':
257*0Sstevel@tonic-gate verbose++;
258*0Sstevel@tonic-gate break;
259*0Sstevel@tonic-gate case 'V':
260*0Sstevel@tonic-gate print_copyright();
261*0Sstevel@tonic-gate return (0);
262*0Sstevel@tonic-gate /* NOTREACHED */
263*0Sstevel@tonic-gate default:
264*0Sstevel@tonic-gate usage();
265*0Sstevel@tonic-gate }
266*0Sstevel@tonic-gate }
267*0Sstevel@tonic-gate
268*0Sstevel@tonic-gate if (list) {
269*0Sstevel@tonic-gate list_privatefile(passwdpath);
270*0Sstevel@tonic-gate return (0);
271*0Sstevel@tonic-gate }
272*0Sstevel@tonic-gate
273*0Sstevel@tonic-gate if (optind >= argc) {
274*0Sstevel@tonic-gate fprintf(stderr, "Need to specify an accessgroup name.\n");
275*0Sstevel@tonic-gate usage();
276*0Sstevel@tonic-gate }
277*0Sstevel@tonic-gate
278*0Sstevel@tonic-gate signal(SIGINT, (void (*)()) catchintr);
279*0Sstevel@tonic-gate
280*0Sstevel@tonic-gate strcpy(accessgroup, argv[optind]);
281*0Sstevel@tonic-gate
282*0Sstevel@tonic-gate if (create) {
283*0Sstevel@tonic-gate if (stat(passwdpath, &stbuf) == 0) {
284*0Sstevel@tonic-gate fprintf(stderr, "%s exists, cannot create it.\n", passwdpath);
285*0Sstevel@tonic-gate fprintf(stderr, "Remove -c option or use the -f option to specify another.\n");
286*0Sstevel@tonic-gate return (1);
287*0Sstevel@tonic-gate }
288*0Sstevel@tonic-gate
289*0Sstevel@tonic-gate if ((tfp = fopen(passwdpath, "w")) == NULL) {
290*0Sstevel@tonic-gate fprintf(stderr, "Could not open \"%s\" for writing.\n", passwdpath);
291*0Sstevel@tonic-gate perror("fopen");
292*0Sstevel@tonic-gate return (1);
293*0Sstevel@tonic-gate }
294*0Sstevel@tonic-gate
295*0Sstevel@tonic-gate tmp = passwdpath;
296*0Sstevel@tonic-gate
297*0Sstevel@tonic-gate printf("Creating WU-FTPD Private file: %s\n", passwdpath);
298*0Sstevel@tonic-gate addrecord(accessgroup, realgroup, "Adding accessgroup", tfp);
299*0Sstevel@tonic-gate
300*0Sstevel@tonic-gate fclose(tfp);
301*0Sstevel@tonic-gate return (0);
302*0Sstevel@tonic-gate }
303*0Sstevel@tonic-gate
304*0Sstevel@tonic-gate #ifdef HAVE_MKSTEMP
305*0Sstevel@tonic-gate strcpy (tmpname, "/tmp/privatepwXXXXXX");
306*0Sstevel@tonic-gate tmp = tmpname;
307*0Sstevel@tonic-gate if ((tfd = mkstemp(tmp)) < 0) {
308*0Sstevel@tonic-gate fprintf(stderr, "Could not open temp file.\n");
309*0Sstevel@tonic-gate return (1);
310*0Sstevel@tonic-gate }
311*0Sstevel@tonic-gate
312*0Sstevel@tonic-gate if ((tfp = fdopen(tfd, "w")) == NULL) {
313*0Sstevel@tonic-gate unlink(tmp);
314*0Sstevel@tonic-gate fprintf(stderr, "Could not open temp file.\n");
315*0Sstevel@tonic-gate return (1);
316*0Sstevel@tonic-gate }
317*0Sstevel@tonic-gate #else
318*0Sstevel@tonic-gate tmp = tmpnam(NULL);
319*0Sstevel@tonic-gate
320*0Sstevel@tonic-gate if ((tfp = fopen(tmp, "w")) == NULL) {
321*0Sstevel@tonic-gate fprintf(stderr, "Could not open temp file.\n");
322*0Sstevel@tonic-gate return (1);
323*0Sstevel@tonic-gate }
324*0Sstevel@tonic-gate #endif
325*0Sstevel@tonic-gate
326*0Sstevel@tonic-gate if ((fp = fopen(passwdpath, "r")) == NULL) {
327*0Sstevel@tonic-gate fprintf(stderr, "Could not open %s file.\n", passwdpath);
328*0Sstevel@tonic-gate fprintf(stderr, "Use -c option to create new one.\n");
329*0Sstevel@tonic-gate return (1);
330*0Sstevel@tonic-gate }
331*0Sstevel@tonic-gate
332*0Sstevel@tonic-gate lineno = 0;
333*0Sstevel@tonic-gate found = 0;
334*0Sstevel@tonic-gate
335*0Sstevel@tonic-gate while (fgets(line, BUFLEN, fp) != NULL) {
336*0Sstevel@tonic-gate lineno++;
337*0Sstevel@tonic-gate
338*0Sstevel@tonic-gate if (found || (line[0] == '#') || (!line[0])) {
339*0Sstevel@tonic-gate fputs(line, tfp);
340*0Sstevel@tonic-gate continue;
341*0Sstevel@tonic-gate }
342*0Sstevel@tonic-gate
343*0Sstevel@tonic-gate strcpy(w, line);
344*0Sstevel@tonic-gate
345*0Sstevel@tonic-gate if ((cp = strchr(w, ':')) == NULL) {
346*0Sstevel@tonic-gate fprintf(stderr, "%s: line %d: invalid record format.\n", passwdpath, lineno);
347*0Sstevel@tonic-gate continue;
348*0Sstevel@tonic-gate }
349*0Sstevel@tonic-gate *cp++ = '\0';
350*0Sstevel@tonic-gate
351*0Sstevel@tonic-gate if ((cp = strchr(cp, ':')) == NULL) {
352*0Sstevel@tonic-gate fprintf(stderr, "%s: line %d: invalid record format.\n", passwdpath, lineno);
353*0Sstevel@tonic-gate continue;
354*0Sstevel@tonic-gate }
355*0Sstevel@tonic-gate *cp++ = '\0';
356*0Sstevel@tonic-gate
357*0Sstevel@tonic-gate if (strcmp(accessgroup, w)) {
358*0Sstevel@tonic-gate fputs(line, tfp);
359*0Sstevel@tonic-gate continue;
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate else {
362*0Sstevel@tonic-gate if (delete) {
363*0Sstevel@tonic-gate if (!confirmed(accessgroup))
364*0Sstevel@tonic-gate terminate();
365*0Sstevel@tonic-gate }
366*0Sstevel@tonic-gate else {
367*0Sstevel@tonic-gate if (realgroup[0] == '\0') {
368*0Sstevel@tonic-gate strcpy(realgroup, cp);
369*0Sstevel@tonic-gate if ((cp = strchr(realgroup, '\n')) != NULL)
370*0Sstevel@tonic-gate *cp = '\0';
371*0Sstevel@tonic-gate }
372*0Sstevel@tonic-gate addrecord(accessgroup, realgroup, "Updating accessgroup", tfp);
373*0Sstevel@tonic-gate }
374*0Sstevel@tonic-gate found = 1;
375*0Sstevel@tonic-gate }
376*0Sstevel@tonic-gate }
377*0Sstevel@tonic-gate
378*0Sstevel@tonic-gate if (!found && !delete)
379*0Sstevel@tonic-gate addrecord(accessgroup, realgroup, "Adding accessgroup", tfp);
380*0Sstevel@tonic-gate else if (!found && delete) {
381*0Sstevel@tonic-gate fprintf(stderr, "%s not found in %s.\n", accessgroup, passwdpath);
382*0Sstevel@tonic-gate terminate();
383*0Sstevel@tonic-gate }
384*0Sstevel@tonic-gate
385*0Sstevel@tonic-gate fclose(fp);
386*0Sstevel@tonic-gate fclose(tfp);
387*0Sstevel@tonic-gate
388*0Sstevel@tonic-gate sprintf(command, "cp %s %s", tmp, passwdpath);
389*0Sstevel@tonic-gate system(command);
390*0Sstevel@tonic-gate unlink(tmp);
391*0Sstevel@tonic-gate return (0);
392*0Sstevel@tonic-gate }
393