1 /*
2 * BRF (Braille-Ready Format) virtual backend
3 *
4 * Copyright (c) 2017 by Samuel Thibault <samuel.thibault@ens-lyon.org>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27 #include "backend-private.h"
28 #include <string.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <pwd.h>
35
main(int argc,char * argv[])36 int main(int argc, char *argv[]) {
37 char *user;
38 char *dir;
39 char *title;
40 char *outfile;
41 char *c;
42 char buffer[4096];
43 ssize_t sizein, sizeout, done;
44 struct passwd *pw;
45 int ret;
46 int fd;
47
48 if (setuid(0)) {
49 /* We need to be root to be able to turn into another user. */
50 fprintf(stderr,"ERROR: cups-brf must be called as root\n");
51 return CUPS_BACKEND_FAILED;
52 }
53
54 if (argc == 1) {
55 /* This is just discovery. */
56 printf("file cups-brf:/ \"Virtual Braille BRF Printer\" \"CUPS-BRF\" \"MFG:Generic;MDL:CUPS-BRF Printer;DES:Generic CUPS-BRF Printer;CLS:PRINTER;CMD:BRF;\"\n");
57 return CUPS_BACKEND_OK;
58 }
59
60 if (argc < 6) {
61 /* Invalid number of parameters. */
62 fprintf(stderr, "ERROR: cups-brf jobid user name nb options [filename]\n");
63 return CUPS_BACKEND_FAILED;
64 }
65
66 if (argc == 7) {
67 /* Explicit file name, open it. */
68 char *filename = argv[6];
69 fd = open(filename, O_RDONLY);
70 if (dup2(fd, STDIN_FILENO) < 0) {
71 fprintf(stderr, "ERROR: opening file \"%s\"\n", filename);
72 return CUPS_BACKEND_FAILED;
73 }
74 }
75
76 /* Now we have everything, turn into the user */
77 user = argv[2];
78 pw = getpwnam(user);
79 if (pw == NULL) {
80 fprintf(stderr, "ERROR: getting user \"%s\" information\n", user);
81 return CUPS_BACKEND_FAILED;
82 }
83 if (setgid(pw->pw_gid)) {
84 fprintf(stderr, "ERROR: turning gid into %u\n", pw->pw_gid);
85 return CUPS_BACKEND_FAILED;
86 }
87 if (setuid(pw->pw_uid)) {
88 fprintf(stderr, "ERROR: turning uid into %u\n", pw->pw_uid);
89 return CUPS_BACKEND_FAILED;
90 }
91
92 /* Now we act as user */
93 umask(0077);
94
95 /* Create BRF directory in $HOME */
96 if (asprintf(&dir, "%s/BRF", pw->pw_dir) < 0) {
97 fprintf(stderr, "ERROR: could not allocate memory\n");
98 return CUPS_BACKEND_FAILED;
99 }
100 fprintf(stderr, "DEBUG: creating directory \"%s\n", dir);
101 ret = mkdir(dir, 0700);
102 if (ret == -1 && errno != EEXIST) {
103 fprintf(stderr, "ERROR: could not create directory \"%s\": %s\n", dir, strerror(errno));
104 return CUPS_BACKEND_FAILED;
105 }
106
107 /* Avoid escaping from the directory */
108 title = argv[3];
109 for (c = title; *c; c++) {
110 if (*c == '/')
111 *c = '_';
112 }
113 /* Avoid hiding the file */
114 while (*title == '.')
115 title++;
116
117 /* Avoid empty title */
118 if (!*title)
119 title = "unknown";
120
121 /* generate mask */
122 if (asprintf(&outfile, "%s/%s.XXXXXX.brf", dir, title) < 0) {
123 fprintf(stderr, "ERROR: could not allocate memory\n");
124 return CUPS_BACKEND_FAILED;
125 }
126
127 /* Create file */
128 fprintf(stderr, "DEBUG: creating file \"%s\n", outfile);
129 fd = mkstemps(outfile, 4);
130 if (fd < 0) {
131 fprintf(stderr, "ERROR: could not create file \"%s\": %s\n", outfile, strerror(errno));
132 return CUPS_BACKEND_FAILED;
133 }
134
135 /* We are all set, copy data. */
136 while (1) {
137 /* Read some. */
138 sizein = read(STDIN_FILENO, buffer, sizeof(buffer));
139 if (sizein < 0) {
140 fprintf(stderr, "ERROR: while reading input: %s\n", strerror(errno));
141 return CUPS_BACKEND_FAILED;
142 }
143 if (sizein == 0)
144 /* We are done! */
145 break;
146
147 /* Write it. */
148 for (done = 0; done < sizein; done += sizeout) {
149 sizeout = write(fd, buffer + done, sizein - done);
150 if (sizeout < 0) {
151 fprintf(stderr, "ERROR: while writing to \"%s\": %s\n", outfile, strerror(errno));
152 return CUPS_BACKEND_FAILED;
153 }
154 }
155 }
156 if (close(fd) < 0) {
157 fprintf(stderr, "ERROR: while closing \"%s\": %s\n", outfile, strerror(errno));
158 return CUPS_BACKEND_FAILED;
159 }
160
161 return CUPS_BACKEND_OK;
162 }
163