s4:rpc_server/lsa: base dcesrv_lsa_LookupNames2() on dcesrv_lsa_LookupNames_common()
[Samba.git] / source3 / client / smbspool_krb5_wrapper.c
blobdee3b4c54bee7e5a8db2a61bcb2a3357a7176c1a
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, ...)
41 PRINTF_ATTRIBUTE(2, 3);
43 #define CUPS_SMB_DEBUG(...) cups_smb_debug(CUPS_SMB_LOG_DEBUG, __VA_ARGS__)
44 #define CUPS_SMB_ERROR(...) cups_smb_debug(CUPS_SMB_LOG_DEBUG, __VA_ARGS__)
46 static void cups_smb_debug(enum cups_smb_dbglvl_e lvl, const char *format, ...)
48 const char *prefix = "DEBUG";
49 char buffer[1024];
50 va_list va;
52 va_start(va, format);
53 vsnprintf(buffer, sizeof(buffer), format, va);
54 va_end(va);
56 switch (lvl) {
57 case CUPS_SMB_LOG_DEBUG:
58 prefix = "DEBUG";
59 break;
60 case CUPS_SMB_LOG_ERROR:
61 prefix = "ERROR";
62 break;
65 fprintf(stderr,
66 "%s: SMBSPOOL_KRB5 - %s\n",
67 prefix,
68 buffer);
72 * This is a helper binary to execute smbspool.
74 * It needs to be installed or symlinked as:
75 * /usr/lib/cups/backend/smb
77 * The permissions of the binary need to be set to 0700 so that it is executed
78 * as root. The binary switches to the user which is passed via the environment
79 * variable AUTH_UID, so we can access the kerberos ticket.
81 int main(int argc, char *argv[])
83 char smbspool_cmd[PATH_MAX] = {0};
84 struct passwd *pwd;
85 char gen_cc[PATH_MAX] = {0};
86 struct stat sb;
87 char *env;
88 uid_t uid = (uid_t)-1;
89 gid_t gid = (gid_t)-1;
90 unsigned long tmp;
91 int cmp;
92 int rc;
94 /* Check if AuthInfoRequired is set to negotiate */
95 env = getenv("AUTH_INFO_REQUIRED");
97 /* If not set, then just call smbspool. */
98 if (env == NULL) {
99 CUPS_SMB_DEBUG("AUTH_INFO_REQUIRED is not set - "
100 "execute smbspool");
101 goto smbspool;
102 } else {
103 CUPS_SMB_DEBUG("AUTH_INFO_REQUIRED=%s", env);
105 cmp = strcmp(env, "username,password");
106 if (cmp == 0) {
107 CUPS_SMB_DEBUG("Authenticate using username/password - "
108 "execute smbspool");
109 goto smbspool;
112 /* if AUTH_INFO_REQUIRED=none */
113 cmp = strcmp(env, "negotiate");
114 if (cmp != 0) {
115 CUPS_SMB_ERROR("Authentication unsupported");
116 fprintf(stderr, "ATTR: auth-info-required=negotiate\n");
117 return CUPS_BACKEND_AUTH_REQUIRED;
121 uid = getuid();
123 CUPS_SMB_DEBUG("Started with uid=%d\n", uid);
124 if (uid != 0) {
125 goto smbspool;
129 * AUTH_UID gets only set if we have an incoming connection over the
130 * CUPS unix domain socket.
132 env = getenv("AUTH_UID");
133 if (env == NULL) {
134 CUPS_SMB_ERROR("AUTH_UID is not set");
135 fprintf(stderr, "ATTR: auth-info-required=negotiate\n");
136 return CUPS_BACKEND_AUTH_REQUIRED;
139 if (strlen(env) > 10) {
140 CUPS_SMB_ERROR("Invalid AUTH_UID");
141 return CUPS_BACKEND_FAILED;
144 errno = 0;
145 tmp = strtoul(env, NULL, 10);
146 if (errno != 0 || tmp >= UINT32_MAX) {
147 CUPS_SMB_ERROR("Failed to convert AUTH_UID=%s", env);
148 return CUPS_BACKEND_FAILED;
150 uid = (uid_t)tmp;
152 pwd = getpwuid(uid);
153 if (pwd == NULL) {
154 CUPS_SMB_ERROR("Failed to find system user: %u - %s",
155 uid, strerror(errno));
156 return CUPS_BACKEND_FAILED;
158 gid = pwd->pw_gid;
160 rc = setgroups(0, NULL);
161 if (rc != 0) {
162 CUPS_SMB_ERROR("Failed to clear groups - %s",
163 strerror(errno));
164 return CUPS_BACKEND_FAILED;
167 CUPS_SMB_DEBUG("Switching to gid=%d", gid);
168 rc = setgid(gid);
169 if (rc != 0) {
170 CUPS_SMB_ERROR("Failed to switch to gid=%u - %s",
171 gid,
172 strerror(errno));
173 return CUPS_BACKEND_FAILED;
176 CUPS_SMB_DEBUG("Switching to uid=%u", uid);
177 rc = setuid(uid);
178 if (rc != 0) {
179 CUPS_SMB_ERROR("Failed to switch to uid=%u - %s",
180 uid,
181 strerror(errno));
182 return CUPS_BACKEND_FAILED;
185 env = getenv("KRB5CCNAME");
186 if (env != NULL && env[0] != 0) {
187 snprintf(gen_cc, sizeof(gen_cc), "%s", env);
189 goto create_env;
192 snprintf(gen_cc, sizeof(gen_cc), "/tmp/krb5cc_%d", uid);
194 rc = lstat(gen_cc, &sb);
195 if (rc == 0) {
196 snprintf(gen_cc, sizeof(gen_cc), "FILE:/tmp/krb5cc_%d", uid);
197 } else {
198 snprintf(gen_cc, sizeof(gen_cc), "/run/user/%d/krb5cc", uid);
200 rc = lstat(gen_cc, &sb);
201 if (rc == 0 && S_ISDIR(sb.st_mode)) {
202 snprintf(gen_cc,
203 sizeof(gen_cc),
204 "DIR:/run/user/%d/krb5cc",
205 uid);
206 } else {
207 #if defined(__linux__)
208 snprintf(gen_cc,
209 sizeof(gen_cc),
210 "KEYRING:persistent:%d",
211 uid);
212 #endif
216 create_env:
218 * Make sure we do not have LD_PRELOAD or other security relevant
219 * environment variables set.
221 #ifdef HAVE_CLEARENV
222 clearenv();
223 #else
225 extern char **environ;
226 environ = calloc(1, sizeof(*environ));
228 #endif
230 CUPS_SMB_DEBUG("Setting KRB5CCNAME to '%s'", gen_cc);
231 setenv("KRB5CCNAME", gen_cc, 1);
233 smbspool:
234 snprintf(smbspool_cmd,
235 sizeof(smbspool_cmd),
236 "%s/smbspool",
237 get_dyn_BINDIR());
239 return execv(smbspool_cmd, argv);