pcnfsd_misc.c revision 1.1 1 /* RE_SID: @(%)/usr/dosnfs/shades_SCCS/unix/pcnfsd/v2/src/SCCS/s.pcnfsd_misc.c 1.5 92/01/24 19:59:13 SMI */
2 /*
3 **=====================================================================
4 ** Copyright (c) 1986,1987,1988,1989,1990,1991 by Sun Microsystems, Inc.
5 ** @(#)pcnfsd_misc.c 1.5 1/24/92
6 **=====================================================================
7 */
8 #include "common.h"
9 /*
10 **=====================================================================
11 ** I N C L U D E F I L E S E C T I O N *
12 ** *
13 ** If your port requires different include files, add a suitable *
14 ** #define in the customization section, and make the inclusion or *
15 ** exclusion of the files conditional on this. *
16 **=====================================================================
17 */
18 #include "pcnfsd.h"
19
20 #include <stdio.h>
21 #include <pwd.h>
22 #include <sys/file.h>
23 #include <signal.h>
24 #include <sys/time.h>
25 #include <sys/stat.h>
26 #include <sys/ioctl.h>
27 #include <netdb.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <ctype.h>
31
32 #ifdef ISC_2_0
33 #include <sys/fcntl.h>
34 #endif
35
36 #ifdef SHADOW_SUPPORT
37 #include <shadow.h>
38 #endif
39
40 #ifdef WTMP
41 int wtmp_enabled = 1;
42 #endif
43
44 #ifdef USE_GETUSERSHELL
45 extern char *getusershell();
46 #endif
47
48 /*
49 **---------------------------------------------------------------------
50 ** Other #define's
51 **---------------------------------------------------------------------
52 */
53
54 #define zchar 0x5b
55
56 char tempstr[256];
57 extern char sp_name[1024]; /* in pcnfsd_print.c */
58
59 /*
60 **=====================================================================
61 ** C O D E S E C T I O N * **=====================================================================
62 */
63 /*
64 **---------------------------------------------------------------------
65 ** Support procedures
66 **---------------------------------------------------------------------
67 */
68
69
70 void
71 scramble(s1, s2)
72 char *s1;
73 char *s2;
74 {
75 while (*s1)
76 {
77 *s2++ = (*s1 ^ zchar) & 0x7f;
78 s1++;
79 }
80 *s2 = 0;
81 }
82
83
84
85 struct passwd *
86 get_password(usrnam)
87 char *usrnam;
88 {
89 struct passwd *p;
90 static struct passwd localp;
91 char *pswd;
92 char *ushell;
93 int ok = 0;
94
95
96 #ifdef SHADOW_SUPPORT
97 struct spwd *sp;
98 int shadowfile;
99 #endif
100
101 #ifdef SHADOW_SUPPORT
102 /*
103 **--------------------------------------------------------------
104 ** Check the existence of SHADOW. If it is there, then we are
105 ** running a two-password-file system.
106 **--------------------------------------------------------------
107 */
108 if (access(SHADOW, 0))
109 shadowfile = 0; /* SHADOW is not there */
110 else
111 shadowfile = 1;
112
113 setpwent();
114 if (shadowfile)
115 (void) setspent(); /* Setting the shadow password
116 * file */
117 if ((p = getpwnam(usrnam)) == (struct passwd *)NULL ||
118 (shadowfile && (sp = getspnam(usrnam)) == (struct spwd *)NULL))
119 return ((struct passwd *)NULL);
120
121 if (shadowfile)
122 {
123 pswd = sp->sp_pwdp;
124 (void) endspent();
125 }
126 else
127 pswd = p->pw_passwd;
128
129 #else
130 p = getpwnam(usrnam);
131 if (p == (struct passwd *)NULL)
132 return ((struct passwd *)NULL);
133 pswd = p->pw_passwd;
134 #endif
135
136 #ifdef ISC_2_0
137 /*
138 **-----------------------------------------------------------
139 ** We may have an 'x' in which case look in /etc/shadow ..
140 **-----------------------------------------------------------
141 */
142 if (((strlen(pswd)) == 1) && pswd[0] == 'x')
143 {
144 struct spwd *shadow = getspnam(usrnam);
145
146 if (!shadow)
147 return ((struct passwd *)NULL);
148 pswd = shadow->sp_pwdp;
149 }
150 #endif
151 localp = *p;
152 localp.pw_passwd = pswd;
153 #ifdef USE_GETUSERSHELL
154
155 setusershell();
156 while(ushell = getusershell()){
157 if(!strcmp(ushell, localp.pw_shell)) {
158 ok = 1;
159 break;
160 }
161 }
162 endusershell();
163 if(!ok)
164 return ((struct passwd *)NULL);
165 #else
166 /*
167 * the best we can do is to ensure that the shell ends in "sh"
168 */
169 ushell = localp.pw_shell;
170 if(strlen(ushell) < 2)
171 return ((struct passwd *)NULL);
172 ushell += strlen(ushell) - 2;
173 if(strcmp(ushell, "sh"))
174 return ((struct passwd *)NULL);
175
176 #endif
177 return (&localp);
178 }
179
180
181 /*
183 **---------------------------------------------------------------------
184 ** Print support procedures
185 **---------------------------------------------------------------------
186 */
187
188 char *
189 mapfont(f, i, b)
190 char f;
191 char i;
192 char b;
193 {
194 static char fontname[64];
195
196 fontname[0] = 0; /* clear it out */
197
198 switch (f) {
199 case 'c':
200 (void)strcpy(fontname, "Courier");
201 break;
202 case 'h':
203 (void)strcpy(fontname, "Helvetica");
204 break;
205 case 't':
206 (void)strcpy(fontname, "Times");
207 break;
208 default:
209 (void)strcpy(fontname, "Times-Roman");
210 goto finis ;
211 }
212 if (i != 'o' && b != 'b') { /* no bold or oblique */
213 if (f == 't') /* special case Times */
214 (void)strcat(fontname, "-Roman");
215 goto finis;
216 }
217 (void)strcat(fontname, "-");
218 if (b == 'b')
219 (void)strcat(fontname, "Bold");
220 if (i == 'o') /* o-blique */
221 (void)strcat(fontname, f == 't' ? "Italic" : "Oblique");
222
223 finis: return (&fontname[0]);
224 }
225
226 /*
227 * run_ps630 performs the Diablo 630 emulation filtering process. ps630
228 * was broken in certain Sun releases: it would not accept point size or
229 * font changes. If your version is fixed, undefine the symbol
230 * PS630_IS_BROKEN and rebuild pc-nfsd.
231 */
232 /* #define PS630_IS_BROKEN 1 */
233
234 void
235 run_ps630(f, opts)
236 char *f;
237 char *opts;
238 {
239 char temp_file[256];
240 char commbuf[256];
241 int i;
242
243 (void)strcpy(temp_file, f);
244 (void)strcat(temp_file, "X"); /* intermediate file name */
245
246 #ifndef PS630_IS_BROKEN
247 (void)sprintf(commbuf, "ps630 -s %c%c -p %s -f ",
248 opts[2], opts[3], temp_file);
249 (void)strcat(commbuf, mapfont(opts[4], opts[5], opts[6]));
250 (void)strcat(commbuf, " -F ");
251 (void)strcat(commbuf, mapfont(opts[7], opts[8], opts[9]));
252 (void)strcat(commbuf, " ");
253 (void)strcat(commbuf, f);
254 #else /* PS630_IS_BROKEN */
255 /*
256 * The pitch and font features of ps630 appear to be broken at
257 * this time.
258 */
259 (void)sprintf(commbuf, "ps630 -p %s %s", temp_file, f);
260 #endif /* PS630_IS_BROKEN */
261
262
263 if (i = system(commbuf)) {
264 /*
265 * Under (un)certain conditions, ps630 may return -1 even
266 * if it worked. Hence the commenting out of this error
267 * report.
268 */
269 /* (void)fprintf(stderr, "\n\nrun_ps630 rc = %d\n", i) */ ;
270 /* exit(1); */
271 }
272 if (rename(temp_file, f)) {
273 perror("run_ps630: rename");
274 exit(1);
275 }
276 return;
277 }
278
279
280
281
282 /*
284 **---------------------------------------------------------------------
285 ** WTMP update support
286 **---------------------------------------------------------------------
287 */
288
289
290 #ifdef WTMP
291
292 #include <utmp.h>
293
294 #ifndef _PATH_WTMP
295 #define _PATH_WTMP "/usr/adm/wtmp"
296 #endif
297
298 void
299 wlogin(name, req)
300 char *name;
301 struct svc_req *req;
302 {
303 extern char *inet_ntoa();
304 struct sockaddr_in *who;
305 struct hostent *hp;
306 char *host;
307 struct utmp ut;
308 int fd;
309
310 if(!wtmp_enabled)
311 return;
312
313 /* Get network address of client. */
314 who = &req->rq_xprt->xp_raddr;
315
316 /* Get name of connected client */
317 hp = gethostbyaddr((char *)&who->sin_addr,
318 sizeof (struct in_addr),
319 who->sin_family);
320
321 if (hp && (strlen(hp->h_name) <= sizeof(ut.ut_host))) {
322 host = hp->h_name;
323 } else {
324 host = inet_ntoa(who->sin_addr);
325 }
326
327 (void) strcpy(ut.ut_line, "PC-NFS");
328 (void) strncpy(ut.ut_name,name,sizeof ut.ut_name);
329 (void) strncpy(ut.ut_host, host, sizeof ut.ut_host);
330 ut.ut_time = time( (time_t *) 0);
331
332 if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
333 (void)write(fd, (char *)&ut, sizeof(struct utmp));
334 (void)close(fd);
335 }
336 }
337 #endif WTMP
338
339 /*
341 **---------------------------------------------------------------------
342 ** Run-process-as-user procedures
343 **---------------------------------------------------------------------
344 */
345
346
347 #define READER_FD 0
348 #define WRITER_FD 1
349
350 static int child_pid;
351
352 static char cached_user[64] = "";
353 static uid_t cached_uid;
354 static gid_t cached_gid;
355
356 static struct sigaction old_action;
357 static struct sigaction new_action;
358 static struct itimerval timer;
359
360 int interrupted = 0;
361 static FILE *pipe_handle;
362
363 static void myhandler()
364 {
365 interrupted = 1;
366 fclose(pipe_handle);
367 kill(child_pid, SIGKILL);
368 msg_out("rpc.pcnfsd: su_popen timeout - killed child process");
369 }
370
371 void start_watchdog(n)
372 int n;
373 {
374 /*
375 * Setup SIGALRM handler, force interrupt of ongoing syscall
376 */
377
378 new_action.sa_handler = myhandler;
379 sigemptyset(&(new_action.sa_mask));
380 new_action.sa_flags = 0;
381 #ifdef SA_INTERRUPT
382 new_action.sa_flags |= SA_INTERRUPT;
383 #endif
384 sigaction(SIGALRM, &new_action, &old_action);
385
386 /*
387 * Set interval timer for n seconds
388 */
389 timer.it_interval.tv_sec = 0;
390 timer.it_interval.tv_usec = 0;
391 timer.it_value.tv_sec = n;
392 timer.it_value.tv_usec = 0;
393 setitimer(ITIMER_REAL, &timer, NULL);
394 interrupted = 0;
395
396 }
397
398 void stop_watchdog()
399 {
400 /*
401 * Cancel timer
402 */
403
404 timer.it_interval.tv_sec = 0;
405 timer.it_interval.tv_usec = 0;
406 timer.it_value.tv_sec = 0;
407 timer.it_value.tv_usec = 0;
408 setitimer(ITIMER_REAL, &timer, NULL);
409
410 /*
411 * restore old signal handling
412 */
413 sigaction(SIGALRM, &old_action, NULL);
414 }
415
416
417
418 FILE *
419 su_popen(user, cmd, maxtime)
420 char *user;
421 char *cmd;
422 int maxtime;
423 {
424 int p[2];
425 int parent_fd, child_fd, pid;
426 struct passwd *pw;
427
428 if (strcmp(cached_user, user)) {
429 pw = getpwnam(user);
430 if (!pw)
431 pw = getpwnam("nobody");
432 if (pw) {
433 cached_uid = pw->pw_uid;
434 cached_gid = pw->pw_gid;
435 strcpy(cached_user, user);
436 } else {
437 cached_uid = (uid_t) (-2);
438 cached_gid = (gid_t) (-2);
439 cached_user[0] = '\0';
440 }
441 }
442 if (pipe(p) < 0) {
443 msg_out("rpc.pcnfsd: unable to create pipe in su_popen");
444 return (NULL);
445 }
446 parent_fd = p[READER_FD];
447 child_fd = p[WRITER_FD];
448 if ((pid = fork()) == 0) {
449 int i;
450
451 for (i = 0; i < 10; i++)
452 if (i != child_fd)
453 (void) close(i);
454 if (child_fd != 1) {
455 (void) dup2(child_fd, 1);
456 (void) close(child_fd);
457 }
458 dup2(1, 2); /* let's get stderr as well */
459
460 (void) setgid(cached_gid);
461 (void) setuid(cached_uid);
462
463 (void) execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
464 _exit(255);
465 }
466 if (pid == -1) {
467 msg_out("rpc.pcnfsd: fork failed");
468 close(parent_fd);
469 close(child_fd);
470 return (NULL);
471 }
472 child_pid = pid;
473 close(child_fd);
474 start_watchdog(maxtime);
475 pipe_handle = fdopen(parent_fd, "r");
476 return (pipe_handle);
477 }
478
479 int
480 su_pclose(ptr)
481 FILE *ptr;
482 {
483 int pid, status;
484
485 stop_watchdog();
486
487 fclose(ptr);
488 if (child_pid == -1)
489 return (-1);
490 while ((pid = wait(&status)) != child_pid && pid != -1);
491 return (pid == -1 ? -1 : status);
492 }
493
494
495 /*
497 ** The following routine reads a file "/etc/pcnfsd.conf" if present,
498 ** and uses it to replace certain builtin elements, like the
499 ** name of the print spool directory. The configuration file
500 ** Is the usual kind: Comments begin with '#', blank lines are ignored,
501 ** and valid lines are of the form
502 **
503 ** <keyword><whitespace><value>
504 **
505 ** The following keywords are recognized:
506 **
507 ** spooldir
508 ** printer name alias-for command
509 ** wtmp yes|no
510 */
511 void
512 config_from_file()
513 {
514 FILE *fd;
515 char buff[1024];
516 char *cp;
517 char *kw;
518 char *val;
519 char *arg1;
520 char *arg2;
521
522 if((fd = fopen("/etc/pcnfsd.conf", "r")) == NULL)
523 return;
524 while(fgets(buff, 1024, fd)) {
525 cp = strchr(buff, '\n');
526 *cp = '\0';
527 cp = strchr(buff, '#');
528 if(cp)
529 *cp = '\0';
530 kw = strtok(buff, " \t");
531 if(kw == NULL)
532 continue;
533 val = strtok(NULL, " \t");
534 if(val == NULL)
535 continue;
536 if(!mystrcasecmp(kw, "spooldir")) {
537 strcpy(sp_name, val);
538 continue;
539 }
540 #ifdef WTMP
541 if(!mystrcasecmp(kw, "wtmp")) {
542 /* assume default is YES, just look for negatives */
543 if(!mystrcasecmp(val, "no") ||
544 !mystrcasecmp(val, "off") ||
545 !mystrcasecmp(val, "disable") ||
546 !strcmp(val, "0"))
547 wtmp_enabled = 0;;
548 continue;
549 }
550 #endif
551 if(!mystrcasecmp(kw, "printer")) {
552 arg1 = strtok(NULL, " \t");
553 arg2 = strtok(NULL, "");
554 (void)add_printer_alias(val, arg1, arg2);
555 continue;
556 }
557 /*
558 ** Add new cases here
559 */
560 }
561 fclose(fd);
562 }
563
564
565 /*
566 ** The following are replacements for the SunOS library
567 ** routines strcasecmp and strncasecmp, which SVR4 doesn't
568 ** include.
569 */
570
571 mystrcasecmp(s1, s2)
572 char *s1, *s2;
573 {
574
575 while (toupper(*s1) == toupper(*s2++))
576 if (*s1++ == '\0')
577 return(0);
578 return(toupper(*s1) - toupper(*--s2));
579 }
580
581 mystrncasecmp(s1, s2, n)
582 char *s1, *s2;
583 int n;
584 {
585
586 while (--n >= 0 && toupper(*s1) == toupper(*s2++))
587 if (*s1++ == '\0')
588 return(0);
589 return(n < 0 ? 0 : toupper(*s1) - toupper(*--s2));
590 }
591
592
593 /*
594 ** strembedded - returns true if s1 is embedded (in any case) in s2
595 */
596
597 int strembedded(s1, s2)
598 char *s1;
599 char *s2;
600 {
601 while(*s2) {
602 if(!mystrcasecmp(s1, s2))
603 return 1;
604 s2++;
605 }
606 return 0;
607 }
608