s3:client:smbspool_krb5_wrapper: fix the non clearenv build.
[Samba.git] / source3 / client / smbspool_krb5_wrapper.c
blobd26a7a6a128ae441e4a3f90f411e0dea70b0fed2
1 /*
2 * Unix SMB/CIFS implementation.
4 * CUPS printing backend helper to execute smbspool
6 * Copyright (C) 2010-2011 Andreas Schneider <asn@samba.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "system/passwd.h"
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include <cups/backend.h>
32 #include "dynconfig/dynconfig.h"
34 #undef calloc
36 enum cups_smb_dbglvl_e {
37 CUPS_SMB_LOG_DEBUG = 0,
38 CUPS_SMB_LOG_ERROR,
40 static void cups_smb_debug(enum cups_smb_dbglvl_e lvl, const char *format, ...);
42 #define CUPS_SMB_DEBUG(...) cups_smb_debug(CUPS_SMB_LOG_DEBUG, __VA_ARGS__)
43 #define CUPS_SMB_ERROR(...) cups_smb_debug(CUPS_SMB_LOG_DEBUG, __VA_ARGS__)
45 static void cups_smb_debug(enum cups_smb_dbglvl_e lvl, const char *format, ...)
47 const char *prefix = "DEBUG";
48 char buffer[1024];
49 va_list va;
51 va_start(va, format);
52 vsnprintf(buffer, sizeof(buffer), format, va);
53 va_end(va);
55 switch (lvl) {
56 case CUPS_SMB_LOG_DEBUG:
57 prefix = "DEBUG";
58 break;
59 case CUPS_SMB_LOG_ERROR:
60 prefix = "ERROR";
61 break;
64 fprintf(stderr,
65 "%s: SMBSPOOL_KRB5 - %s\n",
66 prefix,
67 buffer);
71 * This is a helper binary to execute smbspool.
73 * It needs to be installed or symlinked as:
74 * /usr/lib/cups/backend/smb
76 * The permissions of the binary need to be set to 0700 so that it is executed
77 * as root. The binary switches to the user which is passed via the environment
78 * variable AUTH_UID, so we can access the kerberos ticket.
80 int main(int argc, char *argv[])
82 char smbspool_cmd[PATH_MAX] = {0};
83 struct passwd *pwd;
84 char gen_cc[PATH_MAX] = {0};
85 struct stat sb;
86 char *env;
87 uid_t uid = (uid_t)-1;
88 gid_t gid = (gid_t)-1;
89 unsigned long tmp;
90 int cmp;
91 int rc;
93 uid = getuid();
95 CUPS_SMB_DEBUG("Started with uid=%d\n", uid);
96 if (uid != 0) {
97 goto smbspool;
100 /* Check if AuthInfoRequired is set to negotiate */
101 env = getenv("AUTH_INFO_REQUIRED");
102 if (env == NULL) {
103 CUPS_SMB_ERROR("AUTH_INFO_REQUIRED is not set");
104 fprintf(stderr, "ATTR: auth-info-required=negotiate\n");
105 return CUPS_BACKEND_AUTH_REQUIRED;
108 CUPS_SMB_DEBUG("AUTH_INFO_REQUIRED=%s", env);
109 cmp = strcmp(env, "negotiate");
110 if (cmp != 0) {
111 CUPS_SMB_ERROR("AUTH_INFO_REQUIRED is not set to negotiate");
112 fprintf(stderr, "ATTR: auth-info-required=negotiate\n");
113 return CUPS_BACKEND_AUTH_REQUIRED;
117 * AUTH_UID gets only set if we have an incoming connection over the
118 * CUPS unix domain socket.
120 env = getenv("AUTH_UID");
121 if (env == NULL) {
122 CUPS_SMB_ERROR("AUTH_UID is not set");
123 fprintf(stderr, "ATTR: auth-info-required=negotiate\n");
124 return CUPS_BACKEND_AUTH_REQUIRED;
127 if (strlen(env) > 10) {
128 CUPS_SMB_ERROR("Invalid AUTH_UID");
129 return CUPS_BACKEND_FAILED;
132 errno = 0;
133 tmp = strtoul(env, NULL, 10);
134 if (errno != 0 || tmp >= UINT32_MAX) {
135 CUPS_SMB_ERROR("Failed to convert AUTH_UID=%s", env);
136 return CUPS_BACKEND_FAILED;
138 uid = (uid_t)tmp;
140 pwd = getpwuid(uid);
141 if (pwd == NULL) {
142 CUPS_SMB_ERROR("Failed to find system user: %u - %s",
143 uid, strerror(errno));
144 return CUPS_BACKEND_FAILED;
146 gid = pwd->pw_gid;
148 rc = setgroups(0, NULL);
149 if (rc != 0) {
150 CUPS_SMB_ERROR("Failed to clear groups - %s",
151 strerror(errno));
152 return CUPS_BACKEND_FAILED;
155 CUPS_SMB_DEBUG("Switching to gid=%d", gid);
156 rc = setgid(gid);
157 if (rc != 0) {
158 CUPS_SMB_ERROR("Failed to switch to gid=%u",
159 gid,
160 strerror(errno));
161 return CUPS_BACKEND_FAILED;
164 CUPS_SMB_DEBUG("Switching to uid=%u", uid);
165 rc = setuid(uid);
166 if (rc != 0) {
167 CUPS_SMB_ERROR("Failed to switch to uid=%u",
168 uid,
169 strerror(errno));
170 return CUPS_BACKEND_FAILED;
173 snprintf(gen_cc, sizeof(gen_cc), "/tmp/krb5cc_%d", uid);
175 rc = lstat(gen_cc, &sb);
176 if (rc == 0) {
177 snprintf(gen_cc, sizeof(gen_cc), "FILE:/tmp/krb5cc_%d", uid);
178 } else {
179 snprintf(gen_cc, sizeof(gen_cc), "/run/user/%d/krb5cc", uid);
181 rc = lstat(gen_cc, &sb);
182 if (rc == 0 && S_ISDIR(sb.st_mode)) {
183 snprintf(gen_cc,
184 sizeof(gen_cc),
185 "DIR:/run/user/%d/krb5cc",
186 uid);
187 } else {
188 #if defined(__linux__)
189 snprintf(gen_cc,
190 sizeof(gen_cc),
191 "KEYRING:persistent:%d",
192 uid);
193 #endif
198 * Make sure we do not have LD_PRELOAD or other security relevant
199 * environment variables set.
201 #ifdef HAVE_CLEARENV
202 clearenv();
203 #else
205 extern char **environ;
206 environ = calloc(1, sizeof(*environ));
208 #endif
210 CUPS_SMB_DEBUG("Setting KRB5CCNAME to '%s'", gen_cc);
211 setenv("KRB5CCNAME", gen_cc, 1);
213 smbspool:
214 snprintf(smbspool_cmd,
215 sizeof(smbspool_cmd),
216 "%s/smbspool",
217 get_dyn_BINDIR());
219 return execv(smbspool_cmd, argv);